ANÁLISE DE MALWARE – MINICURSO – CONCEITOS TÉCNICOS ESSENCIAIS

Sumário

Definição de Malware 1

Análise de malware 2

Antivírus 3

Hashes 4

Strings 5

Malware empacotado e ofuscado 5

Formato de arquivo executável portátil (PE Files) 6

.NET, metadados e o formato PE 7

Estrutura do PE 7

Bibliotecas e funções vinculadas 14

Vinculação estática, tempo de execução e dinâmica 14

Funções Importadas 15

Funções exportadas 17

ANTI-REVERSE-ENGINEERING (Anti engenharia reversa) 17

Empacotadores e desempacotadores (Packers and Unpacking) 19

Anatomia do Empacotador 20

Ofuscador ConfuserEx 22

O Stub de descompactação 23

DGA – Algoritmos de geração de domínio 25

Referências 28

 

 

Definição de Malware

O NIST SP 800-83, intitulado “Guide to Malware Incident Prevention and Handling for Desktops and Laptops” (Guia de prevenção e tratamento de incidentes com malware para desktops e laptops), fornece uma interpretação interessante sobre a definição de malware:

“Malware, também conhecido como código malicioso, refere-se a um programa que é secretamente inserido em outro programa com a intenção de destruir dados, executar programas destrutivos ou intrusivos ou comprometer a confidencialidade, integridade ou disponibilidade dos dados, aplicativos, ou sistema operacional “.

Em resumo podemos dizer que Malware é um código usado para executar ações maliciosas. O malware é um software intrusivo projetado para danificar e destruir computadores e sistemas de computadores. Malware é uma contração para “software malicioso”. Exemplos de malware mais comuns são: vírus, worms, trojan, spyware, adware e ransomware.

Abaixo uma breve descrição dos tipos de malware mais comuns:

Vírus – Os vírus são um subgrupo de malware. Um vírus é um software malicioso anexado a um documento ou arquivo que suporta macros para executar seu código e se espalhar de host para host. Depois de baixado, o vírus permanece inativo até que o arquivo seja aberto e em uso. Os vírus são projetados para interromper a capacidade de operação de um sistema. Como resultado, os vírus podem causar problemas operacionais significativos e perda de dados.

Worms – É um software malicioso capaz de replicar-se e espalhar-se rapidamente para os dispositivos. Segundo a Cisco[1] (https://www.cisco.com/c/en/us/products/security/advanced-malware-protection/what-is-malware.html, acesso em abril de 2020), ao contrário dos vírus, os worms não precisam de programas hospedeiros para serem disseminados.

Trojan – Os vírus do tipo Trojan (cavalo de Troia), são normalmente disfarçados de programas de software legítimos. Normalmente, não são projetados para se autoreplicarem, no entanto, no momento em que o usuário faz o download, o vírus Trojan pode obter acesso a dados confidenciais e, em seguida, modificar, bloquear ou excluir os dados.

Spyware – Spyware é um software malicioso projetado para ao invés de simplesmente interromper as operações de um dispositivo, ele direciona informações confidenciais, normalmente financeiras ou pessoais e, pode conceder acesso remoto aos invasores. O keylogger, que registra as teclas digitadas para revelar senhas e informações pessoais, é um tipo de spyware.

Adware – Adware é um software mal-intencionado usado para coletar dados sobre o uso do computador e fornecer anúncios apropriados para você. O adware pode redirecionar seu navegador para sites maliciosos, podendo conter outras pragas virtuais como cavalos de Troia (Trojan) e spyware. Ainda que nem sempre seja perigoso, em alguns casos poderá causar problemas no seu sistema.

Ransomware – é um tipo de software mal-intencionado que obtém acesso a informações confidenciais dentro de um sistema, criptografa essas informações para que o usuário não possa acessá-las e, em seguida, exige um pagamento financeiro para a liberação dos dados. As informações criptografadas só podem ser abertas com uma chave gerada pelo invasor e prometida para o alvo após o pagamento de uma quantia, no entanto, não há garantias de que após o pagamento a chave será fornecida e os dados serão descriptografados.

Malwares Fileless – Fileless (sem arquivo) é um tipo de malware que reside na memória, ou seja, opera a partir da memória do computador da vítima, e não a partir de arquivos armazenados no disco rígido. Seu modo de operação, torna mais difícil sua detecção, visto que, não há arquivos para verificar. Isso também dificulta a análise forense, porque o malware desaparece quando o computador da vítima é reiniciado.

 

Curso - Engenharia Reversa na Forense Digital

Aqui você compreenderá a utilização da Engenharia Reversa aplicada em Forense Digital, bem como a Análise de Malware.

O curso aborda diversos conceitos de forma prática. O estudo é baseado, em sua maioria, no .NET e .NET Core, pois é uma tecnologia que está sempre em evolução, sendo adicionada inclusive em Linux e MAC, ou seja, com o .NET Core, agora é multiplataforma.

Analisando este ambiente, podemos entender que é de extrema importância e urgente necessidade aprender a dissecar malwares desenvolvidos em alguma linguagem do .NET e .NET Core, com C#, VB, etc…

Análise de malware

Análise estática – é onde começamos nossa exploração da análise de malware, que geralmente é o primeiro passo no estudo malware. A análise estática descreve o processo de análise do código ou estrutura de um programa para determinar sua função. O programa em si não é executado neste momento.

Análise dinâmica – ao realizar análises dinâmicas, o analista realmente executa o programa.

Primeiros passos ou passos principais:

  • Usar ferramentas antivírus para confirmar sua maliciosidade.
  • Usar hashes para identificar o malware.
  • Coletar informações das sequências, funções e cabeçalhos de um arquivo.

Cada técnica pode fornecer informações diferentes e as que você usa depende de seus objetivos, no entanto é comum utilizar diversas técnicas e ferramentas para reunir o maior número possível de informações.

Existem alguns serviços online que auxiliam na análise de um malware, como por exemplo o https://www.hybrid-analysis.com/, este é um serviço gratuito de análise de malware para a comunidade que detecta e analisa ameaças desconhecidas usando uma tecnologia exclusiva da Hybrid Analysis. Pode ser interessante enviar o suposto malware para análise neste serviço online, visto que poderá agilizar o trabalho do analista.

Antivírus

O analista de malware, por padrão, ao analisar o malware em potencial pela primeira vez, o ideal é que o primeiro passo seja analisa-lo em vários programas antivírus, que talvez já o tenham identificado. Mas as ferramentas antivírus certamente não são perfeitas. Eles dependem principalmente de um banco de dados trechos identificáveis ​​de códigos suspeitos conhecidos (assinaturas de arquivo), bem como análise comportamental e de correspondência de padrões (heurísticas) para identificar suspeitos arquivos.

É importante observar que os criadores de malware podem modificar facilmente seu código, alterando assim a “assinatura” de seu programa e evitando os scanners de vírus. Além disso, um malware raro geralmente não é detectado pelo software antivírus, isso explica-se facilmente pelo fato de simplesmente não existir no banco de dados.

Dado o fato de que os programas antivírus usam assinaturas e heurísticas diferentes, passa a ser útil executar vários programas antivírus diferentes contra o mesmo programa suspeito. Para executar em vários antivírus diferentes, é recomendado o uso do VirusTotal (http://www.virustotal.com). Neste site é possível carregar um arquivo para verificação por vários motores de antivírus diferentes, ao final, o VirusTotal gera um relatório que fornece o número total de mecanismos que marcaram o arquivo como malicioso, o nome do malware e, se disponível, informações adicionais sobre o malware.

Hashes

Hashing, neste contexto, é um método comum usado para identificar um malware. O software malicioso é analisado usando um programa de extração de HASH, normalmente o MD5 (embora o Secure Hash Algorithm 1 (SHA-1) também seja popular), que produz um único hash que identifica esse malware (um tipo de impressão digital), para esse procedimento pode ser utilizado o HashCalc que pode ser obtido em https://www.slavasoft.com/hashcalc/.

Depois de ter um hash exclusivo para um malware, você pode usá-lo como segue:

  • Compartilhe esse hash com outros analistas para ajudá-los a identificar malware.
  • Pesquise esse hash online para ver se o arquivo já foi identificado.

Um hash de imagem PE (ou hash de arquivo) é semelhante a uma soma de verificação de arquivo, pois o algoritmo de hash produz um resumo da mensagem relacionado à integridade de um arquivo. No entanto, uma soma de verificação é produzida por um algoritmo simples e é usada principalmente para detectar se um bloco de memória no disco está com defeito e se os valores armazenados nele foram corrompidos.

Um hash de arquivo é semelhante a uma soma de verificação, pois também detecta a corrupção do arquivo. No entanto, diferentemente da maioria dos algoritmos de soma de verificação, é muito difícil modificar um arquivo sem alterar o hash do arquivo de seu valor original não modificado. Assim, um hash de arquivo pode ser usado para detectar modificações intencionais e até sutis em um arquivo, como as introduzidas por vírus, hackers ou programas de cavalos de Tróia.

Quando incluído em um certificado, o resumo da imagem deve excluir determinados campos da imagem PE, como a entrada Soma de verificação e Tabela de certificados nos Diretórios opcionais de dados do cabeçalho. Isso ocorre porque o ato de adicionar um certificado altera esses campos e faria com que um valor de hash diferente fosse calculado.

A função Win32 ImageGetDigestStream fornece um fluxo de dados de um arquivo PE de destino com o qual funções de hash. Esse fluxo de dados permanece consistente quando os certificados são adicionados ou removidos de um arquivo PE. Com base nos parâmetros passados para o ImageGetDigestStream, outros dados da imagem do PE podem ser omitidos da computação de hash.

Strings

Pesquisando as strings pode ser uma maneira simples de obter dicas sobre a funcionalidade de um programa, como por exemplo, o malware pode acessar um URL, neste caso será possível identificar a string utilizando o programa. A Microsoft disponibilizou de fora gratuita o programa “strings.exe”, desenvolvido por Mark Russinovich e está disponível em https://docs.microsoft.com/en-us/sysinternals/downloads/strings. No Linux o comando “strings” já é nativo.

Malware empacotado e ofuscado

A ofuscação do código consiste basicamente em transformar o código real em outro menos legível ao ser humano. Normalmente os criadores de malware mais experientes utilizam técnicas de ofuscação e empacotamento para tornar a detecção e análise de seus programas mais difícil. Programas ofuscados são aqueles cuja execução o autor do malware tentou ocultar. Programas empacotados são um subconjunto de programas ofuscados nos quais o programa malicioso é compactado e não pode ser analisado. Ambas as técnicas limitarão severamente suas tentativas de análise o malware.

É importante observar que a ofuscação de código não está restrita ao desejo de ocultar um malware, visto que a ofuscação de código pode ser considerada uma prática de segurança no desenvolvimento de sistemas, pois utilizando essa técnica, o desenvolvedor poderá ter mais uma proteção contra a cópia e violação de propriedade intelectual.

Programas legítimos quase sempre incluem muitas strings. Um Malware que é empacotado ou ofuscado contém muito poucas sequências de caracteres. Se ao pesquisar um programa com o Strings, você descobre que ele tem apenas algumas strings, provavelmente é ofuscado ou compactado.

Formato de arquivo executável portátil (PE Files)

O formato Portable Executable (PE) foi desenvolvido pela Microsoft, sendo padronizado em 1993 pelo Tool Interface Standard Committee (Comitê de Padrões de Interfaces de Ferramentas), formado pela Microsoft, Intel, Borland, Watcom, IBM, entre outras. A Microsoft migrou para o formato PE dos formatos NE de 16 bits com a introdução do sistema operacional Windows NT 3.1 . Todas as versões posteriores do Windows, suportam a estrutura do arquivo.

Esses arquivos são chamados de arquivos Portable Executable (PE) e Common Object File Format (COFF), respectivamente. O formato manteve um suporte legado limitado para preencher a lacuna entre os sistemas baseados em DOS e NT. Por exemplo, os cabeçalhos PE/COFF ainda incluem um programa executável do DOS, que exibe uma mensagem como “Este programa não pode ser executado no modo DOS“. O PE também continua a servir a plataforma Windows em mudança.

Os arquivos executáveis do Windows (.exe) podem ser denominados também como PE Files, em português significa “Arquivo Executavel Portatil”. Esta denominação é procede dos primórdios do Windows onde decidiram criar um formato binário capaz de ser implementado em diversas plataformas (x86, MIPS®, Alpha, entre outros) sem que seja necessário reescrever do zero carregadores de sistemas para memória (system loader) do sistema operacional e outras ferramentas para desenvolvimento. O formato de arquivo Portable Executable (PE) é usado pelos executáveis ​​do Windows (EXE), assim como em DLL, OCX, CPL e SYS.

O formato do arquivo PE é uma estrutura de dados que contém as informações necessárias para o carregador do sistema operacional Windows gerenciar o código executável agrupado. Quase todos os arquivos com código executável que é carregado pelo Windows estão no formato de arquivo PE, embora alguns formatos de arquivo herdados aparecem em raras ocasiões em malware.

Uma das características mais importantes do arquivo PE é que sua estrutura quando armazenada na memória é praticamente a mesma que a definida para o armazenamento em disco. O MS-DOS Header é a estrutura de início de todos os arquivos PE. Contém duas informações importantes: o campo e_magic que contém a assinatura do arquivo executável, inicialmente identificado pelos caracteres MZ ou pelos caracteres hexadecimais 4D 5A.

.NET, metadados e o formato PE

Em um executável .NET, a seção de código PE contém um esboço que chama a entrada de inicialização da máquina virtual CLR , _CorExeMain ou _CorDllMain no mscoree.dll. A máquina virtual utiliza os metadados .NET presentes, cuja raiz, IMAGE_COR20_HEADER (também chamada de “cabeçalho CLR”) é apontada pela entrada IMAGE_DIRECTORY_ENTRY_COMHEADER no diretório de dados do cabeçalho PE. IMAGE_COR20_HEADER se parece muito com o cabeçalho opcional do PE, essencialmente desempenhando seu papel no carregador CLR.

Os dados relacionados ao CLR, incluindo a própria estrutura raiz, geralmente estão contidos na seção de código comum, .text. É composto por alguns diretórios: metadados, recursos incorporados, nomes fortes e alguns para interoperabilidade de código nativo. O diretório de metadados é um conjunto de tabelas que lista todas as entidades .NET distintas no assembly, incluindo tipos, métodos, campos, constantes, eventos, bem como referências entre eles e outros assemblies.

Estrutura do PE

Um arquivo PE é organizado basicamente desta maneira:

  • Cabeçalho DOS – serve para apresentar uma mensagem avisando o usuário que o aplicativo em questão não pode ser utilizado em modo texto. Exemplo: “Este programa não pode ser executado no modo DOS
  • Cabeçalho Windows – aqui estão todas as informações básicas necessárias para que o aplicativo funcione, neste ponto podemos encontrar o número de seções, início das seções, tamanho a execução do código, e diversas outras configurações.
  • Tabela de Seções – Cada linha da tabela de seções é, com efeito, um cabeçalho de seção. Esta tabela segue imediatamente o cabeçalho opcional, se houver. Esse posicionamento é necessário porque o cabeçalho do arquivo não contém um ponteiro direto para a tabela de seção. Em vez disso, a localização da tabela de seção é determinada calculando a localização do primeiro byte após os cabeçalhos. Fonte: https://docs.microsoft.com/pt-br/windows/win32/debug/pe-format?redirectedfrom=MSDN#section-table-section-headers, acesso em 22/04/2020.
  • Seção 1
  • Seção 2
  • Seção N

Variando de acordo com o compilador utilizado e conforme “modificado” ou não pelo usuário, o EXE é divido em seções e cada seção é responsável por uma característica. A seção do arquivo PE contém o conteúdo principal do arquivo, incluindo código, dados, recursos e outros arquivos executáveis. Cada seção tem um cabeçalho e um corpo.

Um aplicativo no Windows NT geralmente possui nove seções predefinidas diferentes, como .text, .bss, .rdata, .data, .rsrc, .edata, .idata, .pdata e .debug. Dependendo do aplicativo, algumas dessas seções são usadas, mas nem todas são usadas.

O código executável: no Windows, todos os segmentos de código residem em uma seção chamada .text section ou CODE. Sabemos que o Windows usa um sistema virtual baseado em página, o que significa ter uma seção de código grande que é mais fácil de gerenciar, tanto para o SO quanto para o desenvolvedor de aplicativos.

Os cabeçalhos de arquivo PE podem fornecer consideravelmente mais informações do que apenas importações. O formato do arquivo PE contém um cabeçalho seguido por uma série de seções. O cabeçalho contém metadados sobre o próprio arquivo. Após o cabeçalho estão as seções reais do arquivo, cada uma das quais contém informações úteis. Como nós ao longo do livro, continuaremos a discutir estratégias para visualizar as informações em cada uma dessas seções.

Os nomes de seção geralmente são consistentes em um compilador, mas podem variar entre compiladores diferentes. Por exemplo, o Visual Studio usa .text para executável código, mas o Borland Delphi usa CODE. O Windows não se importa com o real nome, pois usa outras informações no cabeçalho do PE para determinar como um seção é usada. Além disso, os nomes das seções às vezes são ofuscados para tornar a análise mais difícil. Felizmente, os nomes padrão são usados ​​na maioria das vezes.

A seguir estão as seções mais comuns e interessantes em um arquivo PE:

  • Code Section (.text ou .code ) –  fica armazenado o código compilado, contendo todas as instruções em binário para o funcionamento do programa. Qualquer alteração feita irá resultar numa modificação do arquivo. É nesta secção que normalmente ocorrem as modificações para criar crack de programas e software. A seção .text contém as instruções que a CPU executa. Todas as outras seções armazenam dados e informações de suporte. Geralmente, esta é a única seção que pode ser executada e deve ser a única seção que inclui código.
  • Resource Section (.rsrc ) – é uma seção de recurso, que contém informações de recurso de um módulo. Em muitos casos, mostra ícones e imagens que fazem parte dos recursos do arquivo. A seção .rsrc inclui os recursos usados ​​pelo arquivo executável que não são considerados parte do executável, como ícones, imagens, menus e strings. As strings podem ser armazenadas na seção .rsrc ou no programa principal, mas eles geralmente são armazenados na seção .rsrc para suporte multilíngue.
  • Data Section (.data ) – Esta secção pode ser subdividida em três secções:
  1. BSS Contém todas as variáveis não inicializadas (sem um valor definido).
  2. RDATADados apenas de leitura. Podem ser strings, constantes ou até mesmo dados da Import Table. A seção .rdata normalmente contém as informações de importação e exportação, que são as mesmas informações disponíveis no Dependency Walker e no PEview. Esta seção também pode armazenar outros dados somente leitura usados pelo programa. Às vezes, um arquivo contém uma seção.
  3. DATATodas as outras variáveis que não encaixam em nenhuma das outras secções.
  • Export data section (.edata ) – contém o diretório de exportação para um aplicativo ou DLL. Quando presente, esta seção contém informações sobre os nomes e endereços das funções exportadas. Discutiremos isso com maior profundidade posteriormente.
  • Import data section (.idata ) – contém várias informações sobre funções importadas, incluindo o diretório de importação e a tabela de endereços de importação.
  • Debug information (.debug ) – presente normalmente na fase de desenvolvimento, onde contém informações úteis para o desenvolvedor. No .NET podemos muitas vezes encontrar arquivos PDB, que contém a estrutura necessária para efetuar um debug, se esse arquivo for encontrado em algum software em produção, então o programador foi descuidado, jamais esse arquivo deverá ser distribuído junto com o software.

Figura 1: Cabeçalho do PE, observe as seções .text, .rsrc e .reloc

O número de entradas na tabela de seções é fornecido pelo campo NumberOfSections no cabeçalho do arquivo. As entradas na tabela de seções são numeradas a partir de um (1). As entradas da seção de código e memória de dados estão na ordem escolhida pelo vinculador.

Mais algumas nomenclaturas que podem ser interessantes:

NumberOfSections: define o tamanho da tabela de seções, que segue imediatamente o cabeçalho.

SizeOfOptionalHeader: fica entre a parte superior do cabeçalho opcional e o início da tabela de seções. Esse é o tamanho do cabeçalho opcional necessário para um arquivo executável. Este valor deve ser zero para um arquivo de objeto.

Characteristics: são os sinalizadores de características que indicam um atributo do arquivo de objeto ou imagem. Ele possui um sinalizador chamado Image_File_dll, que possui o valor 0x2000, indicando que a imagem é uma DLL. Também possui sinalizadores diferentes que não são necessários para nós no momento

Image_Optional_Header: esse cabeçalho opcional contém a maioria das informações significativas sobre a imagem, como tamanho inicial da pilha, local do ponto de entrada do programa, endereço base preferido, versão do sistema operacional, informações de alinhamento de seção e assim por diante.

Offset – RawOffset: Indica o posicionamento exato de algo dentro de um arquivo.

VA – Virtual Address: Endereço virtual “absoluto” na memória. O VA “começa” no valor determinado pelo ImageBase, no cabeçalho PE

RVA – Relative Virtual Address: É o endereço relativo contado a partir do início do endereçamento de memória destinado ao aplicativo.

Figura 2: Visualização de cabeçalho com Ghidra da NSA

Figura 3: PE File Format típico. Fonte: Formato de assinatura executável portátil do Windows Authenticode (.docx), acesso em 22/04/2020.

Bibliotecas e funções vinculadas

Uma das informações mais úteis que podemos reunir sobre um executável é a lista de funções que importa e, essas funções são escritas em um programa que é normalmente armazenado em um programa diferente, como em DLL’s, que são bibliotecas que contêm funcionalidades comuns a muitos programas. Isso normalmente é feito para que os desenvolvedores não precisem reimplementar determinadas funcionalidades em vários programas.

As bibliotecas de código podem ser vinculadas de forma estática ou dinâmica, em tempo de execução. Conhecer a biblioteca e/ou o código da biblioteca, além de como ela é vinculada, é fundamental para a compreender o funcionamento do malware.

Vinculação estática, tempo de execução e dinâmica

A vinculação estática é o método menos usado para vincular bibliotecas, embora é comum em programas UNIX e Linux. Quando uma biblioteca está vinculada estaticamente para um executável, todo o código dessa biblioteca é copiado para o executável, que aumenta o tamanho do executável. Ao analisar o código, é difícil diferenciar entre o código vinculado estaticamente e o próprio código do executável, porque nada no cabeçalho do arquivo PE indica que o arquivo contém código vinculado.

Embora impopular em programas amigáveis, a vinculação em tempo de execução é comumente usada em malware, especialmente quando está empacotado ou ofuscado. Executáveis ​​que usam vinculação de tempo de execução, conectam-se a bibliotecas somente quando essa função é necessária, não no início do programa, como nos programas vinculados dinamicamente.

Várias funções do Microsoft Windows permitem que os programadores importem funções vinculadas não listadas no cabeçalho do arquivo de um programa. Destes, as duas funções mais comumente usadas ​​são LoadLibrary e GetProcAddress. As funções LdrGetProcAddress e LdrLoadDll também são usadas.

As funções LoadLibrary e GetProcAddress permitem que um programa tenha a capacidade de acessar qualquer função em qualquer biblioteca do sistema, o que significa que quando essas funções são usadas, você não pode dizer estaticamente quais funções estão sendo vinculadas pelo programa suspeito.

De todos os métodos de vinculação, a vinculação dinâmica é a mais comum e a mais interessante para analistas de malware. Quando as bibliotecas são vinculadas dinamicamente, o SO host procura as bibliotecas necessárias quando o programa é carregado. No entanto, quando o programa chama a função de biblioteca vinculada, essa função executa dentro da biblioteca.

As bibliotecas usadas e as funções chamadas, são sem as partes mais importantes de um programa, e fazer a sua identificação é de extrema importância, dado o fato de que nos permite entender o que o programa faz. O cabeçalho do arquivo PE armazena informações sobre todas as bibliotecas que serão carregadas e todas as funções que serão usadas pelo programa. Por exemplo, se um programa importa a função URLDownloadToFile, você pode pressupor que ele se conecta à Internet para baixar algum conteúdo e armazenar localmente.

Funções Importadas

O cabeçalho do arquivo PE também inclui informações sobre funções específicas usadas por um executável. Os nomes dessas funções do Windows podem fornecer uma boa idéia sobre o que o executável faz. A Microsoft faz um excelente trabalho de documentando a API do Windows por meio da Microsoft Developer Network (MSDN). (Você também encontrará uma lista de funções comumente usadas por malware no Apêndice A.)

Abaixo temos um exemplo de DLL’s que são importadas para a execução do programa:

Figura 4: Bibliotecas e funções importadas

Figura 5: Imports com o PE-Bear, visualização do arquivo Cmder.exe

Quando você executa um PE, o Windows Loader garante que as DLLs corretas (bibliotecas de vínculo dinâmico) sejam importadas se uma função delas estiver sendo usada. Se um programa usar uma função de uma Biblioteca do Windows, a DLL que contém esta função será importada para o espaço de endereço do processo. Quando você executa um PE, o Windows Loader terá esse PE carregado na memória e, portanto, recebe seu próprio processo, que é constituído por “threads“.

Funções exportadas

 As funções exportadas, são em outras palavras, as funções que o arquivo está disponibilizando para outros programas. Como importações, DLLs e EXEs exportam funções para interagir com outros programas e códigos. Normalmente, uma DLL implementa uma ou mais funções e exporta-os para uso por um executável que pode importá-los e usá-los. O arquivo PE contém informações sobre quais funções um arquivo exporta.

Como as DLLs são implementadas especificamente para fornecer a funcionalidade usada pelo EXEs, funções exportadas são mais comuns em DLLs. EXEs não são projetados para fornecer funcionalidade a outros EXEs, e as funções exportadas são raras. Se você descobrir exportações em um executável, elas geralmente fornecerão informações úteis.

Em muitos casos, os autores do software nomeiam suas funções exportadas de uma maneira que forneça informações úteis. Uma convenção comum é usar o nome usado na documentação da Microsoft. Por exemplo, para executar um programa como um serviço, você deve primeiro definir uma função ServiceMain. A presença de uma função exportada chamada ServiceMain informa que o malware é executado como parte de um serviço.

Infelizmente, enquanto a documentação da Microsoft chama essa função ServiceMain, e é comum os programadores fazerem o mesmo, a função pode ter qualquer nome. Portanto, os nomes das funções exportadas são realmente de uso limitado contra malware sofisticado. Se o malware usa exportações, eles frequentemente omitem nomes inteiramente ou usam nomes pouco claros ou enganosos. Você pode visualizar informações de exportação usando o programa Dependency Walker.

Curso - Engenharia Reversa na Forense Digital

Aqui você compreenderá a utilização da Engenharia Reversa aplicada em Forense Digital, bem como a Análise de Malware.

O curso aborda diversos conceitos de forma prática. O estudo é baseado, em sua maioria, no .NET e .NET Core, pois é uma tecnologia que está sempre em evolução, sendo adicionada inclusive em Linux e MAC, ou seja, com o .NET Core, agora é multiplataforma.

Analisando este ambiente, podemos entender que é de extrema importância e urgente necessidade aprender a dissecar malwares desenvolvidos em alguma linguagem do .NET e .NET Core, com C#, VB, etc…

ANTI-REVERSE-ENGINEERING (Anti engenharia reversa)

No S-SDLC (Secure Software Development Life Cycle), ou Ciclo de Vida de Desenvolvimento de Software Seguro, diversas técnicas são aplicadas para proteger o código fonte do sistema. No entanto, as técnicas podem ser uma faca de dois gumes, que se aproveitadas por desenvolvedores de malwares, pode ser um grande complicador para o analista aplicar a engenharia reversa. Algumas medidas aplicadas são: Anti-Disassembly, Anti-Debugging e Anti-VM (a Anti-VM não é utilizada no S-SDLC, visto que não é um meio de proteção querer proteger o programar de ser executado em uma máquina virtual).

Anti-Disassembly – As técnicas utilizadas, visam dificultar, atrasar, evitar e/ou impedir que seja aplicada a engenharia reversa. Ele usa código criado manualmente para fazer com que as ferramentas de análise de desmontagem produzam uma listagem incorreta do programa. Algumas das técnicas mais comuns são: Opcode/assembly code obfuscation, API obfuscation, Junk/spaghetti code, Control flow graph flattening e Jump instruction with same target.

Uma das técnicas mais comuns de anti-disassembly é a ofuscação de código, essa técnica também pode ser aplicada para a segurança da informação no desenvolvimento de software. A ofuscação altera os nomes de identificações (nomes de classe, nomes de métodos, nomes de campos) para nomes aleatórios, de modo que o analista não consiga identificar o código fonte, bem como os programas de análise também tenham a dificuldade de efetuar esse “disassembly”.

Anti-Debugging – A anti-depuração é uma técnica de anti-análise aplicada ao malware, para verificar se está sendo depurado. Isso dificulta bastante o processo de análise.

A técnica mais comum usada por malware é a API do Windows, pois fornece várias funções que podem ser usadas por malware para detectar depuradores. O mais usado é o IsDebuggerPresent. Ele verifica um sinalizador específico no PEB (Process Environment Block) para o campo BeingDebugged, que retornará zero se o processo não estiver sendo executado em um depurador ou diferente de zero se um depurador estiver anexado.

Outra função semelhante é CheckRemoteDebuggerPresent, que verifica se um processo remoto está depurando o atual. O CloseHandle/NtClose é outro uso de malware anti-depuração. Chamar o expedidor com um identificador inválido lança uma exceção de identificador inválida, STATUS_INVALID_HANDLE.

O FindWindow também é usado para encontrar o depurador, fornecendo classe de janela (por exemplo, OLLYDBG).

O malware também pode tirar proveito do sinalizador NtGlobalFlag do PEB no deslocamento 0x68 (que é chamado para verificar se está sendo depurado), verificando se seu valor é igual a 0x70.

Anti-Virtual Machines (Anti-VM) – a maioria dos analistas de malware preferem executar seu malware dentro de um ambiente de máquina virtual para evitar seus computadores sejam afetados pelo malware a ser analisado. Das técnicas mais populares de Anti-VM, temos a verificação de MAC, CPUID e Red Pill.

Um dos métodos usados ​​por desenvolvedores de malware para a identificação de execução em máquinas virtuais é a verificação de endereços conhecidos de MAC, no VMWare são 00:05:69, 00: 0C: 29, 00: 1C: 14, 00:50:56, no VirtualBox é 08:00:27 e assim por diante. A verificação de chaves do registro, processos, verificação de arquivos ou verificação de serviços em execução também são técnicas aplicadas, pois quando uma máquina virtual está em execução, é possível identificar pelos adicionais da plataforma para a compatibilidade com o Sistema Operacional.

“A técnica de CPUID é a mais popular entre essas técnicas. Esta instrução é executada com EAX = 0x1 como entrada e o valor de retorno descreve os recursos do processador. O 31º bit de ECX em uma máquina física será igual a 0. Em uma VM convidada, será igual a 1.  Outro método usando CPUID o executa com EAX = 0x 40000000, que é chamado de ” marca de hypervisor”. O resultado do retorno será o fornecedor de virtualização (“VMwareVMware” para VMWare e “Microsoft HV” para Microsoft). O resultado é armazenado no ECX e EDX.”. Fonte: https://resources.infosecinstitute.com/category/certifications-training/malware-analysis-reverse-engineering/anti-disassembly-anti-debugging-anti-virtual-machine/, acessado em 22/04/2020.

Empacotadores e desempacotadores (Packers and Unpacking)

Os programas empacotadores, tornaram-se extremamente populares entre os criadores de malware, pois auxiliam na sua ocultação perante os software’s antivírus. A maioria dos empacotadores é fácil de usar e está disponível gratuitamente. A análise estática não é útil contra um programa compactado; o malware compactado precisará ser descompactado para poder ser analisado estaticamente, o que torna a análise mais complicada e desafiadora. Os empacotadores são usados ​​nos executáveis ​​por dois motivos principais: reduzir programas ou impedir a detecção ou análise.

Anatomia do Empacotador

Quando o malware é compactado, um analista normalmente tem acesso apenas ao arquivo compactado e não pode examinar o programa descompactado original ou o programa que compactou o malware. Para descompactar um executável, precisamos desfazer o trabalho realizado pelo empacotador, o que exige que entendamos como o empacotador opera.

Todos os empacotadores pegam um arquivo executável como entrada e produzem um executável arquivo como saída. O executável compactado é compactado, criptografado ou de outra forma transformado, dificultando o reconhecimento e a engenharia reversa.

A maioria dos empacotadores (com o foco em malware) usam um algoritmo de compactação para compactar o executável original. Um empacotador projetado para dificultar a análise do arquivo pode criptografar o executável original e emprega técnicas de anti-engenharia reversa, como anti-disassembling, anti-debugging ou anti-VM.

Para manter a funcionalidade do programa original, um programa de embalagem precisa armazenar as informações de importação do programa. Ao desembalar um programa, reconstruir a seção de importação pode às vezes ser desafiador e demorado, mas é necessário analisar a funcionalidade do programa.

Figura 6: Representação de Packer e Unpacker. Fonte: https://www.joesecurity.org/blog/8506317946374998489, acessado em 29/04/2020.

Basicamente o fluxo de trabalho de Packing, Unpacking e execução é o seguinte:

1) Arquivo original – Se você olhar para o seu arquivo PE, ele contém um cabeçalho, uma seção de código (.text) e algumas seções adicionais (.data, .rsrc e etc.). Muito importante, todo o código está disponível para análise estática. É relativamente simples encontrar padrões de código exclusivos no segmento de código para detectar o arquivo como malicioso.

2) Packing – Neste momento, o compactador gerará um arquivo PE totalmente novo, contendo novo cabeçalho, na sequência, o arquivo original será transformado. A transformação poderá envolver algum algoritmo de compactação, uma operação criptográfica ou ambos. Este arquivo após transformado é copiado para o novo arquivo e, o final, um pequeno código Stub é adicionado a este novo arquivo PE, afim de, no momento da execução ser possível reverter a transformação.

3) Carregando a fase 1 do arquivo compactado – Quando o arquivo compactado é iniciado, ele é mapeado para a memória virtual. Em seguida, o stub de descompactação é chamado para reverter a operação de compactação e/ou criptografia. Como resultado, o arquivo original é “restaurado” na memória. Existem duas possibilidades em que o arquivo é restaurado. O arquivo PE completo compactado é substituído pelo original ou restaurado em um endereço de memória diferente.

4) Carregando a fase 2 do arquivo compactado – Assim que o arquivo original for “restaurado”, o stub transferirá a execução para o arquivo “restaurado”. O arquivo restaurado será executado normalmente.

Ofuscador ConfuserEx

Um excelente exemplo de “ofuscador e compressor” gratuito é o ConfuserEx, esse programa é recomendado para a proteção de código fonte, não contendo algumas funções utilizadas pelo desenvolvedor de malware, como por exemplo a técnica de Anti-VM, entretanto para o desenvolvimento de software seguro é muito interessante.

Algumas das funções disponíveis no ConfuserEx:

  • Symbol renaming (Support WPF/BAML)
  • Protection against debuggers/profilers
  • Protection against memory dumping
  • Protection against tampering (method encryption)
  • Control flow obfuscation
  • Constant/resources encryption
  • Reference hiding proxies
  • Disable decompilers
  • Embedding dependency
  • Compressing output
  • Extensible plugin API

Figura 7: ConfuserEx. O programa pode ser obtido gratuitamente em: https://github.com/petterlopes/ConfuserEx.

O Stub de descompactação

O stub da descompactação executa três etapas:

  • Descompacta o executável original na memória
  • Resolve todas as importações do executável original
  • Transfere a execução para o ponto de entrada original (OEP)

Os executáveis ​​não compactados são carregados pelo sistema operacional. Com programas compactados, o stub de descompactação é carregado pelo sistema operacional e, em seguida, o stub de descompactação carrega o programa original. O ponto de entrada de código dos pontos executáveis ​​para o descompactar o esboço em vez do código original. O programa original é geralmente armazenado em uma ou mais seções extras do arquivo.

Entender as diferentes partes do stub é fundamental para descompactar o executável. O stub do pacote é geralmente pequeno, uma vez que não contribui para a principal funcionalidade do programa, e sua função é geralmente simples: descompactar o executável original. Se você tentar realizar análises estáticas no pacote, você analisará o stub (esboço) e não o programa original.

Segundo abordado por especialistas da Fireye, Moritz Raabe e Willian Ballenthin (2016), uma abordagem popular usada pelos autores de malware para proteger seu software é a embalagem ou empacotamento. No processo de empacotamento, a compactação de um programa transforma o executável em um formato compactado e/ou ofuscado. O malware compactado pode impedir sua análise, pois exige que você restaure primeiro os dados descompactados. No entanto, por outro lado, como empacotar é incomum, simplesmente sinalizar arquivos compactados é uma maneira confiável de identificar executáveis ​​suspeitos.

Os arquivos compactados podem ser facilmente detectados por meio de recursos como: um pequeno número de funções importadas, um alto nível de entropia ou características de cabeçalho de seção suspeitas. Assim, enquanto a embalagem oculta as strings, faz com que um binário malicioso se destaque como um “dedo duro”.

Em vez disso, os atacantes geralmente codificam sequências sensíveis individualmente, sem compactar o arquivo binário inteiro. Isso significa que durante o tempo de execução, o programa decodifica as strings antes do uso. Por exemplo, o programa pode decodificar as sequências incondicionalmente durante a rotina de inicialização ou decodificar as sequências imediatamente antes de seu uso. De qualquer maneira, as sequências de caracteres não são visíveis no executável em disco e o arquivo não é trivial para detectar. Abaixo temos um exemplo simples de ofuscação de cadeia usando a operação XOR.

Figura 8: Exemplo simples de ofuscação de cadeia usando a operação XOR. Fonte: https://www.fireeye.com/blog/threat-research/2016/06/automatically-extracting-obfuscated-strings.html, acessado em 23/04/2020.

Ainda para os especialistas da Fireye, Moritz Raabe e Willian Ballenthin (2016), a construção manual de strings é outra técnica que os autores de malware costumam usar para ocultar strings. Em vez de armazenar uma sequência consecutiva de bytes para formar uma sequência de caracteres, uma coleção de instruções recria as sequências de caracteres byte a byte. Ainda para os autores, como strings.exe procura uma sequência de caracteres imprimíveis, não é possível identificar a sequência legível por humanos porque os caracteres são intercalados com os dados do código de operação. Ocultar cadeias de caracteres, como caminhos do sistema de arquivos e nomes de domínio, torna mais difícil para os analistas forenses decidir se um arquivo é malicioso ou não.

DGA – Algoritmos de geração de domínio

Um algoritmo de geração de domínio é um programa desenvolvido para gerar nomes de domínio de uma maneira específica. Os invasores desenvolveram DGAs para que o malware possa gerar rapidamente uma lista de domínios que ele pode usar para os sites que fornecem instruções e recebem informações do malware (geralmente chamado de “comando e controle” ou C2).

Era mais comum, os invasores manter uma lista estática de domínios maliciosos, então os defensores poderiam facilmente pegar essa lista e começar a bloquear e derrubar esses sites. Ao usar um algoritmo para criar a lista de domínios, os atacantes também tornam mais difícil para os defensores saber ou prever quais domínios serão usados ​​do que se tivessem uma lista simples de domínios. Como os softwares e os fornecedores de segurança agem rapidamente para bloquear e derrubar domínios maliciosos que o malware usa, então os atacantes desenvolveram o DGA especificamente para burlar essa proteção.

O Mitre sugere que os cibercriminosos podem usar os DGAs (Domain Generation Algorithms) para identificar dinamicamente um destino para o tráfego de comando e controle, em vez de confiar em uma lista de endereços IP ou domínios estáticos. Isso tem a vantagem de tornar muito mais difícil para os defensores bloquear, rastrear ou assumir o canal de comando e controle, pois pode haver milhares de domínios em que o malware pode verificar instruções.

Ainda para o Mitre, os DGAs podem assumir a forma de sequências aparentemente aleatórias ou “sem sentido” (ex: istgmxdejdnxuyla.ru) quando constroem nomes de domínio, gerando cada letra. Como alternativa, alguns DGAs empregam palavras inteiras como unidade concatenando palavras juntas em vez de letras (por exemplo: cityjulydish.net). Muitos DGAs são baseados em tempo, gerando um domínio diferente para cada período de tempo (por hora, diariamente, mensalmente, etc.). Outros incorporam também um valor inicial para dificultar a previsão de domínios futuros para os defensores.

De acordo com o Mitre, os adversários podem usar DGAs para fins de canais de fallback . Quando o contato é perdido com o servidor primário de comando e controle, o malware pode empregar um DGA como meio para restabelecer o comando e o controle.

Segundo o Mitre, a detecção de domínios gerados dinamicamente pode ser desafiadora devido ao número de algoritmos DGA diferentes, à evolução constante das famílias de malware e à crescente complexidade dos algoritmos. Existem inúmeras abordagens para detectar um nome de domínio gerado pseudoaleatoriamente, incluindo o uso de análise de frequência, cadeias de Markov, entropia, proporção de palavras do dicionário, proporção de vogais e outros caracteres e muito mais. Os domínios CDN podem acionar essas detecções devido ao formato de seus nomes de domínio. Além de detectar um domínio DGA com base no nome, outra abordagem mais geral para detectar um domínio suspeito é verificar nomes registrados recentemente ou domínios raramente visitados.

Para o Mitre, as abordagens de aprendizado de máquina para detectar domínios DGA foram desenvolvidas e obtiveram sucesso em aplicativos. Uma abordagem é usar métodos N-Gram para determinar uma pontuação de aleatoriedade para sequências de caracteres usadas no nome de domínio. Se a pontuação de aleatoriedade for alta e os domínios não estiverem na lista de permissões (CDN, etc), poderá ser determinado se um domínio ou relacionado a um host ou DGA legítimo. Outra abordagem é usar o Deep Learning para classificar domínios como gerados por DGA.

Referências

https://www.devmedia.com.br/windows-portable-executable/857, acesso em 22/04/2020.

https://seguranca-informatica.pt/os-segredos-de-um-exe-pe-file-portable-executable/, acesso em 22/04/2020.

https://www.devmedia.com.br/windows-portable-executable/857, acesso em 22/04/2020.

https://resources.infosecinstitute.com/2-malware-researchers-handbook-demystifying-pe-file/ , acesso em 22/04/2020.

https://resources.infosecinstitute.com/malware-researchers-handbook/#article , acesso em 22/04/2020.

https://www.wikiwand.com/en/Portable_Executable , acesso em 22/04/2020.

https://docs.microsoft.com/pt-br/windows/win32/debug/pe-format?redirectedfrom=MSDN , acesso em 22/04/2020.

https://www.hardware.com.br/tutoriais/executavel-win32/, acesso em 22/04/2020.

https://grazfather.github.io/re/malware/ida/2016/09/18/Anti-Disassembly.html, acesso em 22/04/2020.

https://resources.infosecinstitute.com/category/certifications-training/malware-analysis-reverse-engineering/anti-disassembly-anti-debugging-anti-virtual-machine/, acesso em 22/04/2020.

https://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/Authenticode_PE.docx, acesso em 22/04/2020.

https://attack.mitre.org/techniques/T1483/, acesso em 22/04/2020.

https://blogs.cisco.com/security/talos/threat-spotlight-dyre, acesso em 22/04/2020.

https://unit42.paloaltonetworks.com/threat-brief-understanding-domain-generation-algorithms-dga/, acesso em 22/04/2020.

https://www.fireeye.com/blog/threat-research/2019/05/learning-to-rank-strings-output-for-speedier-malware-analysis.html, acesso em 22/04/2020.

https://www.fireeye.com/blog/threat-research/2016/06/automatically-extracting-obfuscated-strings.html, acesso em 22/04/2020.

https://www.joesecurity.org/blog/8506317946374998489, acesso em 29/04/2020.

https://www.cisco.com/c/en/us/products/security/advanced-malware-protection/what-is-malware.html, acesso em 30/04/2020.

  1. Cisco Systems, Inc., empresa de tecnologia especialista em soluções para cibersegurança.