Olá pessoal! Antecipando o início de um novo fluxo no curso de
engenharia reversa, estamos compartilhando com você uma tradução de um material muito interessante. Aprecie a leitura

Os últimos dois anos podem ser chamados de anos de hackers de ransomware. O ransomware foi, sem dúvida, o tipo de malware mais popular. No entanto, no final dos últimos anos, começamos a observar seu declínio na popularidade e seu aumento em favor dos mineiros. É possível que em 2018 essa tendência só cresça.
Do ponto de vista da vítima, isso é um alívio, pois os mineiros não são tão perigosos quanto o ransomware. Sim, eles diminuem a velocidade do sistema, mas assim que você se livrar deles, você poderá continuar usando o computador como antes. Seus dados não são roubados ou perdidos, como é o caso do vírus ransomware.
Da perspectiva de um pesquisador de malware, os mineradores são decepcionantes. Eles não fornecem material novo o suficiente para uma análise mais profunda, principalmente porque são baseados em componentes de código aberto conhecidos com pouca ou nenhuma confusão ou furtividade.
No entanto, de tempos em tempos, encontramos mineradores usando truques interessantes. Recentemente, vimos uma técnica chamada "Heaven's Gate", que permite injeções em processos de 64 bits de gerenciadores de inicialização de 32 bits. Essa idéia não é nova, sua primeira implementação remonta a 2009, mas é interessante ver como foi implementada em uma nova forma, obtida diretamente "da natureza".
Iniciantes na análise de vírus podem ler um guia sobre o que é o Portal do Céu e como abordar sua análise.
Materiais para análise
Esse padrão foi encontrado na continuação da campanha
Ngay (mais sobre isso
aqui ). A verificação da biografia dessas amostras me levou ao
artigo @_qaz_qaz , que descreve uma campanha anterior com uma amostra semelhante. No entanto, sua análise não incluiu a tecnologia Heaven's Gate.
Análise comportamental
Para ver a injeção mencionada, precisamos executar a amostra em um sistema de 64 bits. Vemos que ele lança a essência do notebook, com os parâmetros específicos para a mineração de criptomoedas:

Observando as linhas da memória no ProcessExplorer, vemos que este não é um notebook de verdade, mas o
minerador XMRig Monero.

Portanto, no momento, temos certeza de que a imagem do notebook na memória foi provavelmente substituída pelo método RunPE (Process Hollowing).
O conta-gotas principal é de 32 bits, mas transfere a carga útil para um notebook de 64 bits:

O mais interessante é que esse tipo de injeção não é suportado pela API oficial do Windows. Podemos ler / gravar na memória de processos de 32 bits de um aplicativo de 64 bits (usando a API WoW64), mas não vice-versa.
No entanto, existem algumas soluções não oficiais, como uma técnica chamada "Porta do Céu".
Revisão da porta do céu
A técnica da porta do céu foi descrita pela primeira vez em 2009 por um hacker com o apelido Roy G. Biv. Posteriormente, muitas implementações foram criadas, por exemplo, a biblioteca
Wow64ext ou, com base nela,
W64oWoW64 . Em seu blog em 2015, Alex Ionescu descreveu
medidas para combater essa técnica .
Vamos ver como isso funciona.
Executando processos de 32 bits no Windows de 64 bits
Cada processo de 32 bits em execução em uma versão de 64 bits do Windows é executado em um subsistema
WoW64 especial que emula um ambiente de 32 bits. Você pode desenhar uma analogia com uma sandbox de 32 bits criada dentro de um processo de 64 bits. Então, primeiro, um ambiente de processo de 64 bits é criado. E já dentro dele é criado um ambiente de 32 bits. O aplicativo é executado neste ambiente de 32 bits, mas não tem acesso à sua parte de 64 bits.
Se digitalizarmos um processo de 32 bits de fora usando um scanner de 64 bits, veremos que ele possui DLLs de 32 e 64 bits. Mais importante, ele possui duas versões do NTDLL: 32 bits (carregado no diretório SysWow64) e 64 bits (carregado no diretório System32):

No entanto, o próprio processo de 32 bits não vê a parte de 64 bits e está limitado ao uso de DLLs de 32 bits. Para injetar em um processo de 64 bits, você precisa usar as versões de 64 bits das funções correspondentes.
Segmentos de código
Para obter acesso à parte restrita do ambiente, precisamos entender como o isolamento é feito. Acontece que tudo é bem simples. A execução de código de 32 e 64 bits está disponível através de um endereço de segmento de código diferente: 32 bits - 0x23 e 64 bits - 0x33.
Se chamarmos o endereço da maneira usual, o modo usado para interpretá-lo será definido por padrão. No entanto, podemos solicitar explicitamente uma alteração usando o código de montagem.
Dentro do mineiro: implementação da porta do céu
Não realizarei uma análise completa desse mineiro, como já foi descrito
aqui . Vamos direto para o lugar onde a diversão começa. O programa malicioso verifica seu ambiente e, se detectar que está sendo executado em um sistema de 64 bits, usa uma maneira diferente de injetar no processo de 64 bits:

Após algumas verificações anti-análise, ele cria um novo processo suspenso de 64 bits (neste caso, um bloco de notas):

Esse é o destino no qual a carga maliciosa será implementada.
Como aprendemos anteriormente, para incorporar a carga útil em um processo de 64 bits, precisamos usar as funções de 64 bits apropriadas.
Primeiro, o carregador de inicialização passa o processamento NTDLL de 64 bits:

O que acontece dentro da função
get_ntdll
requer uma explicação mais detalhada. Como explicação, também podemos dar uma olhada no
código semelhante na biblioteca ReWolf.
Para acessar a parte de 64 bits do ambiente do processo, precisamos trabalhar com seletores de segmentos. Vamos ver como o malware entra no modo de 64 bits.

Parece que esse código foi copiado diretamente da biblioteca aberta:
https://github.com/rwfpl/rewolf-wow64ext/blob/master/src/internal.h#L26O seletor de segmento 0x33 é empurrado para a pilha. Em seguida, o malware chama a seguinte linha: (dessa maneira, o endereço da próxima linha também é colocado na pilha).

O endereço que foi
retf
pilha é corrigido adicionando 5 bytes e é definido após
retf
:

No final, a instrução RETF é chamada. RETF é um "retorno distante" e, diferentemente do RET normal, permite especificar não apenas o endereço do qual você deseja continuar a execução, mas também um segmento. Como argumentos, são necessários dois DWORDs da pilha. Assim, quando RETF é executado, o endereço de retorno de retorno se torna:
0x33: 0x402A50Graças ao segmento alterado, o código que começa no endereço especificado é interpretado como 64 bits. Portanto, o código que o depurador vê é de 32 bits ...

... na verdade de 64 bits.
Para alternar rapidamente as visualizações, eu uso a função PE-bear:

E aqui está a aparência desse pedaço de código se for interpretado como de 64 bits:

Portanto, o código executado aqui é responsável por mover o conteúdo do registro R12 para uma variável na pilha e, em seguida, retornar ao modo de 32 bits. Isso é feito para obter o
TEB (Thread Information Block) de 64 bits, do qual obtemos o
PEB (Process Environment Block) de 64 bits
daqui - analisamos um
código semelhante .
Um PEB de 64 bits é usado como ponto de partida para encontrar uma versão de 64 bits do NTDLL. Esta parte é implementada de maneira bastante
trivial (uma implementação "básica" deste método pode ser encontrada
aqui ), usando um ponteiro para as bibliotecas carregadas, que são um dos campos na estrutura do PEB. Então, do PEB, obtemos um campo chamado
Ldr :
Ldr é uma estrutura do tipo
_PEB_LDR_DATA
. Ele contém uma entrada chamada
InMemoryOrderModuleList
:

Esta lista contém todas as bibliotecas carregadas que estão presentes na memória do processo em estudo. Examinamos a lista até encontrarmos a biblioteca em que estamos interessados, no nosso caso, é NTDLL. É exatamente isso que a função
get_ntdll
acima
get_ntdll
. Para encontrar um nome adequado, ele chama a seguinte função, designada como
is_ntdll_lib
, que verifica o nome da biblioteca em relação ao ntdll.dll por caracteres. O equivalente a
esse código acaba.

Se os nomes corresponderem, o endereço da biblioteca será retornado para alguns registros:

Uma vez que encontramos o NTDLL, precisamos apenas obter os endereços das funções correspondentes. Podemos fazer isso observando a tabela de exportação da biblioteca:

As seguintes funções são recuperadas:
- NttUnmapViewOfSection
- NtGetContextThread
- NtAllocateVirtualMemory
- NtReadVirtualMemory
- NtWriteVirtualMemory
- NtSetContextThread.
Como sabemos, essas funções são típicas da técnica RunPE. Primeiro, NtUnmapViewOfSection é usado para remover o mapeamento do arquivo PE original. Em seguida, no processo remoto, a memória é alocada e um novo PE é gravado. No final, o contexto do processo é alterado para que a execução inicie no módulo incorporado.
Os endereços das funções são armazenados e posteriormente chamados (semelhante a
este código) para controlar o processo remoto.
Conclusão
Até agora, os autores de mineradores não mostraram muita criatividade. Eles alcançam seus objetivos confiando em componentes de código aberto. O caso descrito reflete bem essa tendência, pois foi usada uma implementação pronta.
A Porta do Céu existe há vários anos. Alguns programas maliciosos o utilizam para aumentar a
furtividade . Mas, no caso desse minerador, os autores provavelmente procuraram maximizar o desempenho usando a carga útil que melhor se ajusta à arquitetura de destino.
Só isso. Você pode descobrir mais sobre o nosso curso
aqui .