Introdução
O Elastic Security Labs analisa diversos malwares que passam por nossos pipelines de busca de ameaças e filas de telemetria. Recentemente, nos deparamos com uma nova família de malware chamada DOUBLELOADER, vista junto com o infostealer RHADAMANTHYS. Um atributo interessante do DOUBLELOADER é que ele é protegido por um ofuscador de código aberto, o ALCATRAZ, lançado pela primeira vez em 2023. Embora esse projeto tenha tido suas raízes na comunidade de hackers de jogos, ele também foi observado no espaço do crime eletrônico e foi usado em intrusões direcionadas.
O objetivo desta postagem é abordar diversas técnicas de ofuscação empregadas pela ALCATRAZ e, ao mesmo tempo, destacar métodos para combater essas técnicas como analistas de malware. Essas técnicas incluem achatamento de fluxo de controle, mutação de instruções, desdobramento constante, ocultação de constantes LEA, truques antidesmontagem e ofuscação de ponto de entrada.
Principais conclusões
- O ofuscador de código aberto ALCATRAZ foi visto em um novo malware implantado junto com infecções por RHADAMANTHYS
- Técnicas de ofuscação, como o achatamento do fluxo de controle, continuam a servir como obstáculos para os analistas
- Ao compreender as técnicas de ofuscação e como combatê-las, as organizações podem melhorar sua capacidade de selecionar e analisar efetivamente binários protegidos.
- Elastic Security Labs lança ferramentas para desofuscar binários protegidos por ALCATRAZ são lançados com esta postagem
CARREGADOR DUPLO
A partir de dezembro passado, nossa equipe observou um malware backdoor genérico associado a infecções do ladrão RHADAMANTHYS . Com base no caminho do PDB, esse malware é autodescrito como DOUBLELOADER.
Este malware aproveita chamadas de sistema como NtOpenProcess, NtWriteVirtualMemory, NtCreateThreadEx iniciando código não suportado na área de trabalho/gerenciador de arquivos do Windows (explorer.exe). O malware coleta informações do host, solicita uma versão atualizada de si mesmo e começa a se comunicar com um IP codificado (185.147.125.81) armazenado no binário.
Os exemplos do DOUBLELOADER incluem uma seção não padrão (.0Dev) com permissões executáveis. Esta é uma marca de ferramenta deixada com base no identificador do autor para a ferramenta de ofuscação binária, ALCATRAZ.
Ofuscadores como o ALCATRAZ acabam aumentando a complexidade na triagem de malware. Seu principal objetivo é dificultar as ferramentas de análise binária e aumentar o tempo do processo de engenharia reversa por meio de diferentes técnicas; como ocultar o fluxo de controle ou dificultar o acompanhamento da descompilação. Abaixo está um exemplo de fluxo de controle ofuscado de uma função dentro de DOUBLELOADER.
O restante da postagem se concentrará nas diversas técnicas de ofuscação usadas pela ALCATRAZ. Usaremos o primeiro estágio do DOUBLELOADER junto com exemplos básicos de código para destacar os recursos do ALCATRAZ.
ALCATRAZ
Visão geral do ALCATRAZ
Alcatraz é um ofuscador de código aberto lançado inicialmente em janeiro de 2023. Embora o projeto seja reconhecido pela comunidade de hackers de jogos como uma ferramenta fundamental para o aprendizado de técnicas de ofuscação, ele também tem sido alvo de abusos por parte de grupos de crimes eletrônicos e APT.
A base de código do Alcatraz contém 5 recursos principais centrados em técnicas de ofuscação de código padrão, juntamente com melhorias para ofuscar o ponto de entrada. Seu fluxo de trabalho segue um formato padrão bin2bin , o que significa que o usuário fornece um binário compilado e, após as transformações, ele receberá um novo binário compilado. Essa abordagem é particularmente atraente para hackers de jogos/desenvolvedores de malware devido à sua facilidade de uso, exigindo esforço mínimo e nenhuma modificação no nível do código-fonte.
O desenvolvedor pode escolher ofuscar todas ou funções específicas, bem como escolher quais técnicas de ofuscação aplicar a cada função. Após a compilação, o arquivo é gerado com a string (obf) anexada ao final do nome do arquivo.
Técnicas de ofuscação em ALCATRAZ
As seções a seguir abordarão as diversas técnicas de ofuscação implementadas pelo ALCATRAZ.
Ofuscação de ponto de entrada
Lidar com um ponto de entrada ofuscado é como ter um pneu furado no início de uma viagem em família. A ideia é concentrar-se em confundir analistas e ferramentas binárias, onde não fica diretamente claro onde o programa começa, causando confusão logo no início do processo de análise.
A seguir está a visão de um ponto de entrada limpo (0x140001368) de um programa não ofuscado dentro do IDA Pro.
Ao habilitar a ofuscação do ponto de entrada, o ALCATRAZ move o ponto de entrada e inclui código adicional com um algoritmo para calcular o novo ponto de entrada do programa. Abaixo está um trecho da visão descompilada do ponto de entrada ofuscado.
Como ALCATRAZ é um ofuscador de código aberto, podemos encontrar o código do ponto de entrada personalizado para ver como o cálculo é realizado ou reverter nosso próprio exemplo ofuscado. Em nossa descompilação, podemos ver que o algoritmo usa alguns campos do cabeçalho PE, como Size of the Stack Commit, Time Date Stamp , juntamente com os primeiros quatro bytes da seção .0dev . Esses campos são analisados e então usados com operações bit a bit, como rotação à direita (ROR) e exclusivo-ou (XOR), para calcular o ponto de entrada.
Abaixo está um exemplo de saída do script Python do IDA (Apêndice A) que analisa o PE e encontra o verdadeiro ponto de entrada, confirmando o ponto de partida original (0x140001368) com a amostra não ofuscada.
Anti-desmontagem
Desenvolvedores de malware e ofuscadores usam truques anti-desmontagem para confundir ou quebrar os desmontadores, a fim de dificultar a análise estática. Essas técnicas exploram as fraquezas durante varreduras lineares e desmontagem recursiva, impedindo a reconstrução limpa do código, onde o analista é forçado a corrigir manualmente ou automaticamente as instruções subjacentes.
O ALCATRAZ implementa uma forma dessa técnica modificando quaisquer instruções que comecem com o byte 0xFF adicionando uma instrução de salto curto ( 0xEB) na frente. O byte 0xFF pode representar o início de múltiplas instruções válidas que lidam com chamadas, saltos indiretos e pushes na pilha. Ao adicionar o salto curto 0xEB na frente, isso efetivamente salta para o próximo byte 0xFF. Embora não seja complexo, o dano é causado pela desmontagem e pela quebra, exigindo algum tipo de intervenção.
Para corrigir essa técnica específica, o arquivo pode ser corrigido substituindo cada ocorrência do byte 0xEB por NOPs. Após a aplicação do patch, o código é restaurado para um estado mais limpo, permitindo que a seguinte instrução call seja desmontada corretamente.
Mutação de Instrução
Uma técnica comum usada por ofuscadores é a mutação de instruções, onde as instruções são transformadas de uma forma que preserva seu comportamento original, mas torna o código mais difícil de entender. Frameworks como Tigress ou Perses são ótimos exemplos de pesquisa de ofuscação em torno de mutação de instruções.
Abaixo está um exemplo desta técnica implementada pelo ALCATRAZ, onde qualquer adição entre dois registros é alterada, mas sua equivalência semântica é mantida intacta. A instrução simples add é transformada em 5 instruções diferentes (push, not, sub, pop, sub).
Para corrigir isso, podemos usar a correspondência de padrões para encontrar essas instruções 5 juntas, desmontar os bytes para descobrir quais registradores estão envolvidos e, em seguida, usar um montador como o Keystone para gerar os bytes correspondentes corretos.
Desdobramento constante
Essa técnica de ofuscação é predominante em toda a amostra DOUBLELOADER e é um método amplamente utilizado em várias formas de malware. O conceito aqui está focado em inverter o processo de compilação; onde em vez de otimizar cálculos que são conhecidos em tempo de compilação, o ofuscador “desdobra” essas constantes, tornando a desmontagem e a descompilação complexas e confusas. Abaixo está um exemplo simples desta técnica onde a constante conhecida (46) é dividida em duas operações matemáticas.
No DOUBLELOADER, encontramos essa técnica sendo usada sempre que valores imediatos são movidos para um registrador. Esses valores imediatos são substituídos por múltiplas operações bit a bit que mascaram esses valores constantes, interrompendo assim qualquer contexto e o fluxo do analista. Por exemplo, na desmontagem abaixo no lado esquerdo, há uma instrução de comparação do valor EAX no endereço (0x18016CD93). Ao revisar as instruções anteriores, não fica óbvio ou claro qual deve ser o valor EAX devido a vários cálculos bit a bit obscuros. Se depurarmos o programa, podemos ver que o valor EAX está definido como 0.
Para limpar essa técnica de ofuscação, podemos confirmar seu comportamento com nosso próprio exemplo, onde podemos usar o seguinte código-fonte e ver como a transformação é aplicada.
#include <iostream>
int add(int a, int b)
{
return a + b;
}
int main()
{
int c;
c = add(1, 2);
printf("Meow %d",c);
return 0;
}
Após a compilação, podemos visualizar a desmontagem da função main na versão limpa à esquerda e ver essas duas constantes (2,1) movidas para os registradores EDX e ECX. No lado direito, está a versão transformada, as duas constantes estão escondidas entre as instruções recém-adicionadas.
Ao usar técnicas de correspondência de padrões, podemos procurar essas sequências de instruções, emular as instruções para executar vários cálculos para obter os valores originais de volta e, então, corrigir os bytes restantes com NOPs para garantir que o programa ainda será executado.
Ofuscação LEA
Semelhante à técnica discutida anteriormente, a ofuscação LEA (Load Effective Address) se concentra em obscurecer os valores imediatos associados às instruções LEA. Um cálculo aritmético com subtração seguirá diretamente após a instrução LEA para calcular o valor original pretendido. Embora isso possa parecer uma alteração pequena, ela pode ter um impacto significativo na quebra de referências cruzadas para strings e dados — que são essenciais para uma análise binária eficaz.
Abaixo está um exemplo dessa técnica dentro do DOUBLELOADER, onde o valor do registrador RAX é disfarçado por meio de um padrão de carregamento de um valor inicial (0x1F4DFCF4F) e, em seguida, subtração (0x74D983C7) para nos dar um novo valor computado (0x180064B88).
Se formos até esse endereço dentro do nosso exemplo, seremos levados para a seção de dados somente leitura, onde podemos encontrar a string referenciada bad array new length.
Para corrigir essa técnica, podemos usar a correspondência de padrões para encontrar essas instruções específicas, realizar o cálculo e então reconstruir uma nova instrução LEA. No modo de 64 bits, o LEA usa endereçamento relativo ao RIP, de modo que o endereço é calculado com base no ponteiro de instrução atual (RIP). No final, terminamos com uma nova instrução que se parece com isto: lea rax, [rip - 0xFF827].
Abaixo estão as etapas para produzir esta instrução final:
Com essas informações, podemos usar o IDA Python para corrigir todos esses padrões. Abaixo está um exemplo de uma instrução LEA fixa.
Ofuscação de fluxo de controle
O achatamento do fluxo de controle é uma técnica poderosa de ofuscação que interrompe a estrutura tradicional do fluxo de controle de um programa, eliminando construções convencionais como ramificações condicionais e loops. Em vez disso, ele reestrutura a execução usando um despachante centralizado, que determina o próximo bloco básico a ser executado com base em uma variável de estado, tornando a análise e a descompilação significativamente mais difíceis. Abaixo está um diagrama simples que representa as diferenças entre um fluxo de controle não achatado e achatado.
Nossa equipe observou essa técnica em vários malwares, como o DOORME , e não é nenhuma surpresa, neste caso, que o fluxo de controle simplificado seja um dos principais recursos do ofuscador ALCATRAZ. Para abordar o desnivelamento, nos concentramos em ferramentas estabelecidas usando o plugin IDA D810 escrito pelo pesquisador de segurança Boris Batteux.
Começaremos com nosso programa de exemplo anterior usando a função comum _security_init_cookie usada para detectar estouros de buffer. Abaixo está o diagrama de fluxo de controle da função de inicialização de cookie em formato não ofuscado. Com base no gráfico, podemos ver que há seis blocos básicos, duas ramificações condicionais e podemos seguir facilmente o fluxo de execução.
Se pegarmos a mesma função e aplicarmos o recurso de achatamento de fluxo de controle do ALCATRAZ, o fluxo de controle do programa parecerá muito diferente com 22 blocos básicos, 8 ramificações condicionais e um novo despachante. Na figura abaixo, os blocos preenchidos com cores representam os blocos básicos anteriores da versão não ofuscada, os blocos restantes em branco representam o código ofuscador adicionado usado para despachar e controlar a execução.
Se dermos uma olhada na descompilação, podemos ver que a função agora está dividida em partes diferentes dentro de um loop while onde uma nova variável state é usada para guiar o programa junto com resquícios da ofuscação, incluindo instruções popf/pushf .
Para limpar esta função, o D810 aplica duas regras diferentes (UnflattenerFakeJump, FixPredecessorOfConditionalJumpBlock) que aplicam transformações de microcódigo para melhorar a descompilação.
2025-04-03 15:44:50,182 - D810 - INFO - Starting decompilation of function at 0x140025098
2025-04-03 15:44:50,334 - D810 - INFO - glbopt finished for function at 0x140025098
2025-04-03 15:44:50,334 - D810 - INFO - BlkRule 'UnflattenerFakeJump' has been used 1 times for a total of 3 patches
2025-04-03 15:44:50,334 - D810 - INFO - BlkRule 'FixPredecessorOfConditionalJumpBlock' has been used 1 times for a total of 2 patches
Quando atualizamos o descompilador, o achatamento do fluxo de controle é removido e o pseudocódigo é limpo.
Embora este seja um bom exemplo, corrigir a ofuscação do fluxo de controle pode muitas vezes ser um processo manual e demorado, que depende da função. Na próxima seção, reuniremos algumas das técnicas que aprendemos e as aplicaremos ao DOUBLELOADER.
Limpeza de uma função DOUBLELOADER
Um dos desafios ao lidar com ofuscação em malware não são tanto as técnicas individuais de ofuscação, mas quando as técnicas são em camadas. Além disso, no caso do DOUBLELOADER, grandes porções de código são colocadas em blocos de função com limites ambíguos, tornando-o difícil de analisar. Nesta seção, veremos um exemplo prático mostrando o processo de limpeza de uma função DOUBLELOADER protegida pelo ALCATRAZ.
Ao iniciar a exportação Start , uma das primeiras chamadas vai para loc_18016C6D9. Esta parece ser uma entrada para uma função maior, no entanto o IDA não consegue criar uma função corretamente devido a instruções indefinidas em 0x18016C8C1.
Se rolarmos até este endereço, podemos ver que a primeira interrupção se deve à técnica anti-desmontagem de salto curto que vimos anteriormente na postagem do blog (EB FF).
Depois de corrigir 6 ocorrências próximas desta mesma técnica, podemos voltar ao endereço inicial (0x18016C6D9) e usar o recurso MakeFunction. Embora a função seja descompilada, ela ainda estará muito ofuscada, o que não é ideal para nenhuma análise.
Voltando à desmontagem, podemos ver a técnica de ofuscação LEA usada nesta função abaixo, onde a constante de string ”Error” agora é recuperada usando a solução anterior.
Outro exemplo abaixo mostra a transformação de um parâmetro ofuscado para uma chamada LoadIcon onde o parâmetro lpIconName é limpo para 0x7f00 (IDI_APPLICATION).
Agora que a descompilação melhorou, podemos finalizar a limpeza removendo a ofuscação do fluxo de controle com o plugin D810. Abaixo está uma demonstração mostrando os efeitos antes e depois.
Esta seção abordou um cenário real de trabalho para limpar uma função maliciosa ofuscada protegida pelo ALCATRAZ. Embora os relatórios de análise de malware geralmente mostrem os resultados finais, uma boa parte do tempo costuma ser gasta inicialmente trabalhando para remover a ofuscação e corrigir o binário para que ele possa ser analisado adequadamente.
Scripts Python IDA
Nossa equipe está lançando uma série de scripts IDA Python de prova de conceito usados para lidar com as técnicas de ofuscação padrão impostas pelo ofuscador ALCATRAZ. Eles devem servir como exemplos básicos ao lidar com essas técnicas e devem ser usados para fins de pesquisa. Infelizmente, não existe uma solução mágica para lidar com ofuscação, mas ter alguns exemplos e estratégias gerais pode ser valioso para enfrentar desafios semelhantes no futuro.
YARA
O Elastic Security criou regras YARA para identificar essa atividade.
Observações
Os seguintes observáveis foram discutidos nesta pesquisa.
| Observável | Tipo | Nome | Referência |
|---|---|---|---|
3050c464360ba7004d60f3ea7ebdf85d9a778d931fbf1041fa5867b930e1f7fd | SHA256 | DoubleLo.dll | CARREGADOR DUPLO |
Referências
Os seguintes itens foram referenciados ao longo da pesquisa acima:
