Capítulo 1 - Técnicas Básicas Estáticas
Iniciamos nossa exploração da análise de malware com a análise estática, que geralmente é o primeiro passo no estudo de malware. A análise estática descreve o processo de examinar o código ou a estrutura de um programa para determinar sua função, sem executar o programa nesse momento.
Escaneamento com Antivírus: Um Primeiro Passo Útil
Ao analisar malware potencial, um bom primeiro passo é executá-lo em vários programas antivírus, que podem já tê-lo identificado. No entanto, as ferramentas antivírus não são perfeitas. Elas se baseiam principalmente em um banco de dados de assinaturas de código suspeito conhecido, bem como em análises comportamentais e de correspondência de padrões (heurísticas) para identificar arquivos suspeitos.
Um dos problemas é que os criadores de malware podem facilmente modificar seu código, alterando a assinatura do programa e conseguindo assim evitar os scanners de vírus. Além disso, malware raro frequentemente não é detectado pelo software antivírus porque simplesmente não está no banco de dados. Por fim, as heurísticas, embora muitas vezes eficazes na identificação de código malicioso desconhecido, podem ser contornadas por malwares novos e únicos.
Como os diferentes programas antivírus utilizam assinaturas e heurísticas distintas, é útil executar vários programas antivírus contra a mesma amostra de malware suspeita. Sites como o VirusTotal (http://www.virustotal.com/) permitem que você faça o upload de um arquivo para escaneamento por vários motores antivírus. O VirusTotal gera um relatório que fornece o número total de motores que marcaram o arquivo como malicioso, o nome do malware e, se disponível, informações adicionais sobre o malware.
Hashing: A Impressão Digital do Malware
O hashing é um método comum utilizado para identificar de forma única malware. O software malicioso é processado por um programa de hashing que gera um hash exclusivo que identifica esse malware (uma espécie de impressão digital). A função de hash Message-Digest Algorithm 5 (MD5) é a mais comumente usada para análise de malware, embora a Secure Hash Algorithm 1 (SHA-1) também seja popular.
Por exemplo, ao usar o programa md5deep, disponível gratuitamente, para calcular o hash do programa Solitaire que vem com o Windows, o seguinte resultado seria gerado:
O hash gerado é 373e7a863a1a345c60edb9e20ec3231. O calculador de hashes WinMD5, que possui uma interface gráfica, pode calcular e exibir hashes para vários arquivos ao mesmo tempo.
Uma vez que você tenha um hash exclusivo para uma amostra de malware, pode usá-lo da seguinte forma:
Usar o hash como um rótulo: Facilita a identificação do malware em suas análises.
Compartilhar esse hash com outros analistas: Ajuda na identificação e troca de informações sobre malware.
Pesquisar esse hash online: Verifica se o arquivo já foi identificado anteriormente em bancos de dados ou fóruns de segurança.
Encontrando Strings
Uma string em um programa é uma sequência de caracteres, como “the.” Um programa contém strings se, por exemplo, imprimir uma mensagem, conectar-se a uma URL ou copiar um arquivo para um local específico.
Pesquisar por strings pode ser uma maneira simples de obter pistas sobre a funcionalidade de um programa. Por exemplo, se o programa acessar uma URL, essa URL será armazenada como uma string no código.
Quando o programa Strings busca por strings ASCII e Unicode em um executável, ele ignora o contexto e a formatação, permitindo que analise qualquer tipo de arquivo e detecte strings em todo o arquivo. O programa busca por sequências de três ou mais caracteres ASCII e Unicode, seguidas de um caractere de terminação de string (NULL Byte).
Às vezes, as strings detectadas pelo programa Strings não são strings reais. Por exemplo, se o Strings encontrar a sequência de bytes 0x56, 0x50, 0x33, 0x00, ele interpretará isso como a string VP3. No entanto, esses bytes podem não representar essa string; podem ser um endereço de memória, instruções da CPU ou dados usados pelo programa.
Malware Empacotado e Ofuscado
Os criadores de malware frequentemente utilizam técnicas de empacotamento ou ofuscação para tornar seus arquivos mais difíceis de detectar ou analisar. Programas ofuscados são aqueles cuja execução o autor do malware tentou ocultar. Os programas empacotados são um subconjunto de programas ofuscados, onde o programa malicioso é comprimido e não pode ser analisado. Ambas as técnicas limitam severamente suas tentativas de análise estática do malware.
Programas legítimos quase sempre incluem muitas strings, enquanto malware empacotado ou ofuscado contém muito poucas strings. Se, ao buscar uma string em um programa usando o Strings, você encontrar apenas algumas, é provável que o arquivo esteja ofuscado ou empacotado, sugerindo que ele pode ser malicioso. Para investigar mais a fundo, você provavelmente precisará usar técnicas além da análise estática.
Nota: Códigos empacotados e ofuscados geralmente incluem pelo menos as funções LoadLibrary e GetProcAddress, que são utilizadas para carregar e acessar funções adicionais.
Empacotando Arquivos
Quando um programa empacotado é executado, um pequeno programa “wrapper” (invólucro) também é executado para descomprimir o arquivo empacotado e, em seguida, executar o arquivo descompactado. Quando um programa empacotado é analisado estaticamente, apenas o pequeno programa wrapper pode ser dissecado. (O Capítulo 18 discute empacotamento e desempacotamento em mais detalhes.)
Detectando Empacotadores com PEiD
Uma maneira de detectar arquivos empacotados é usar o programa PEiD. Você pode usar o PEiD para detectar o tipo de empacotador ou compilador utilizado para construir uma aplicação, o que facilita a análise do arquivo empacotado.
Nota: O desenvolvimento e suporte para o PEiD foram descontinuados desde abril de 2011, mas ainda é a melhor ferramenta disponível para detecção de empacotadores e compiladores (De acordo com o livro que já é um pouco antigo. Retoolkit tem várias outras alternativas). Em muitos casos, ele também identificará qual empacotador foi usado para empacotar o arquivo.
Nota2: Muitos plug-ins do PEiD executarão o executável de malware sem aviso! Além disso, como todos os programas, especialmente aqueles usados para análise de malware, o PEiD pode estar sujeito a vulnerabilidades. Por exemplo, a versão 0.92 do PEiD continha um buffer overflow que permitia que um atacante executasse código arbitrário, possibilitando que um autor de malware criasse um programa para explorar a máquina do analista de malware. Certifique-se de usar a versão mais recente do PEiD.
Formato de Arquivo Executável Portátil (PE)
Até agora, discutimos ferramentas que escaneiam executáveis sem considerar seu formato. No entanto, o formato de um arquivo pode revelar muito sobre a funcionalidade do programa.
O formato de arquivo Portable Executable (PE) é utilizado por executáveis do Windows, código objeto e DLLs. O formato de arquivo PE é uma estrutura de dados que contém as informações necessárias para que o carregador do sistema operacional Windows gerencie o código executável encapsulado. Quase todos os arquivos com código executável que são carregados pelo Windows estão no formato PE, embora alguns formatos de arquivo legados apareçam raramente em malwares.
Os arquivos PE começam com um cabeçalho que inclui informações sobre o código, o tipo de aplicação, funções de biblioteca necessárias e requisitos de espaço. As informações contidas no cabeçalho PE são de grande valor para o analista de malware.
Esses dados ajudam a entender como o malware opera, quais dependências ele possui e quais recursos do sistema ele pode estar utilizando. Portanto, a análise do cabeçalho PE é um passo importante na identificação de comportamentos e funcionalidades maliciosas.
Bibliotecas e Funções Vinculadas
Uma das informações mais úteis que podemos obter sobre um executável é a lista de funções que ele importa. Imports são funções usadas por um programa, mas armazenadas em outro, como bibliotecas de código que contêm funcionalidades comuns a muitos programas. As bibliotecas podem ser conectadas ao executável principal por meio de vinculação.
Os programadores vinculam funções de bibliotecas a seus programas para evitar reimplementar funcionalidades em vários programas. As bibliotecas podem ser vinculadas de três maneiras: estática, em tempo de execução ou dinâmica. Saber como o código da biblioteca está vinculado é crucial para a compreensão do malware, pois as informações que podemos encontrar no cabeçalho do arquivo PE dependem desse método de vinculação.
Uma das informações mais úteis que podemos obter sobre um executável é a lista de funções que ele importa. Imports são funções usadas por um programa, mas armazenadas em outro, como bibliotecas de código que contêm funcionalidades comuns a muitos programas. As bibliotecas podem ser conectadas ao executável principal por meio de vinculação.
Os programadores vinculam funções de bibliotecas a seus programas para evitar reimplementar funcionalidades em vários programas. As bibliotecas podem ser vinculadas de três maneiras: estática, em tempo de execução ou dinâmica. Saber como o código da biblioteca está vinculado é crucial para a compreensão do malware, pois as informações que podemos encontrar no cabeçalho do arquivo PE dependem desse método de vinculação.
Vinculação Estática, em Tempo de Execução e Dinâmica
Vinculação Estática: É o método menos utilizado no Windows, mas comum em programas UNIX e Linux. Quando uma biblioteca é vinculada estaticamente a um executável, todo o código da biblioteca é copiado para o executável, o que aumenta o tamanho do arquivo. Isso dificulta a diferenciação entre o código vinculado e o código original do programa, pois o cabeçalho PE não indica que o arquivo contém código vinculado.
Vinculação em Tempo de Execução: Bastante comum em malwares, especialmente aqueles empacotados ou ofuscados, a vinculação em tempo de execução conecta-se às bibliotecas apenas quando a função é necessária, em vez de no início do programa, como na vinculação dinâmica. Funções como LoadLibrary e GetProcAddress são usadas para importar funções vinculadas que não estão listadas no cabeçalho do arquivo. Essas funções permitem que um programa acesse qualquer função de qualquer biblioteca no sistema, o que significa que, ao usá-las, não é possível saber estaticamente quais funções estão sendo vinculadas pelo programa suspeito.
Vinculação Dinâmica: É a mais comum e interessante para analistas de malware. Quando bibliotecas são vinculadas dinamicamente, o sistema operacional hospedeiro procura as bibliotecas necessárias quando o programa é carregado. Quando o programa chama a função da biblioteca vinculada, essa função é executada dentro da própria biblioteca. O cabeçalho do arquivo PE armazena informações sobre cada biblioteca que será carregada e cada função que será usada pelo programa. Identificar essas bibliotecas e funções é particularmente importante, pois permite fazer suposições sobre o comportamento do programa. Por exemplo, se um programa importa a função URLDownloadToFile, é possível inferir que ele se conecta à Internet para baixar conteúdo e armazená-lo localmente.
O livro aborda uma ferramenta para obter a lista de DLLs requeridas por um executável PE, mas já está antigo, para novas ferramentas a respeito procurar nesse link]
Convenções de Nomenclatura de Funções
Ao avaliar funções Windows desconhecidas, vale observar algumas convenções de nomenclatura comuns que podem aparecer e causar confusão se você não as reconhecer.
Sufixo "Ex": Funções com o sufixo "Ex" (como CreateWindowEx) indicam uma versão atualizada e incompatível com a função original. Esse sufixo é adicionado quando a Microsoft lança uma nova versão de uma função sem remover a antiga, garantindo compatibilidade retroativa. Em casos de múltiplas atualizações, algumas funções podem até ter dois sufixos "Ex".
Sufixos "A" e "W": Funções que aceitam strings como parâmetro geralmente incluem uma letra "A" ou "W" no final do nome (por exemplo, CreateDirectoryW). Essas letras não aparecem na documentação oficial da função, mas indicam que existem duas versões dela: a versão "A" lida com strings ASCII, enquanto a "W" aceita strings de caractere largo (Unicode). Para buscar essas funções na documentação da Microsoft, é importante remover o sufixo "A" ou "W".
Funções Importadas e Exportadas no Formato PE
Funções Importadas
No cabeçalho de arquivos PE, as funções importadas indicam quais funções específicas um executável utiliza. Isso é útil, pois os nomes dessas funções do Windows oferecem pistas sobre as funcionalidades do programa. A Microsoft documenta amplamente a API do Windows neste [link], o que permite que analistas (e desenvolvedores de malware) verifiquem as descrições das funções utilizadas. (Muitas funções comuns em malware estão listadas no Apêndice A do livro).
Funções Exportadas
DLLs e EXEs podem exportar funções, permitindo que outros programas as utilizem. DLLs geralmente contêm várias funções exportadas que são projetadas para serem usadas por outros executáveis. Em contraste, EXEs raramente exportam funções, pois são feitos para operar de forma independente. A presença de funções exportadas em um EXE pode, portanto, ser um indício interessante, especialmente em análises de malware.
Alguns desenvolvedores nomeiam suas funções exportadas de forma descritiva, muitas vezes seguindo os nomes padrão da documentação Microsoft, o que ajuda a entender a função. Um exemplo comum é ServiceMain, que indica que um programa pode rodar como serviço. No entanto, o nome das funções exportadas é de uso limitado em malware sofisticado, pois autores de malware podem renomear essas funções de forma ambígua ou confusa, dificultando a análise.
Estrutura de Cabeçalhos e Seções do Arquivo PE
O formato do arquivo PE (Portable Executable) é composto por um cabeçalho seguido por várias seções. O cabeçalho contém informações essenciais sobre o arquivo, como tipo de aplicação, dependências e configurações de execução. Em seguida, as seções do arquivo armazenam diferentes tipos de dados e instruções. As principais seções são:
.text: Esta seção contém o código executável, ou seja, as instruções que a CPU irá processar. Geralmente, é a única seção permitida a conter instruções e, portanto, a única a ser executável.
.rdata: Armazena dados de leitura apenas, incluindo informações de importação e exportação, e outros dados acessados globalmente. Em algumas compilações, essas informações podem estar em seções .idata e .edata.
.data: Guarda dados globais que podem ser acessados de qualquer lugar do programa. Dados locais, no entanto, não são armazenados aqui e sim em outras áreas de execução.
.rsrc: Contém recursos auxiliares do executável, como ícones, imagens, menus e strings de texto. Esses elementos são armazenados aqui principalmente para suporte multilíngue e interface do usuário.
.idata e .edata: Seções opcionais para armazenar informações de funções de importação (.idata) e exportação (.edata) separadamente. Quando ausentes, essa informação fica no .rdata.
.pdata: Exclusiva para executáveis de 64 bits, guarda informações para manipulação de exceções durante a execução.
.reloc: Armazena dados sobre a realocação de arquivos de biblioteca necessários para a execução do executável em endereços de memória diferentes dos originalmente designados.
Nomes das Seções
As seções geralmente mantêm nomes padrão dependendo do compilador. Por exemplo, o Visual Studio usa .text para código executável, enquanto o Borland Delphi usa CODE. Embora esses nomes possam ser modificados ou ofuscados para dificultar a análise, o Windows se orienta por outras informações no cabeçalho PE para determinar a função de cada seção.
Tabela Resumo das Seções:
Nome da Seção
Função
.text
Contém o código executável
.rdata
Dados somente leitura e informações de importação/exportação
.data
Dados globais acessíveis por todo o programa
.idata
Informações de funções de importação (opcional)
.edata
Informações de funções de exportação (opcional)
.pdata
Manipulação de exceções (64 bits)
.rsrc
Recursos auxiliares (ícones, imagens, menus)
.reloc
Dados para relocação de bibliotecas
Sumário do Cabeçalho PE
O cabeçalho PE fornece informações cruciais que ajudam a entender o funcionamento de um malware. A tabela a seguir resume os principais campos do cabeçalho PE e o tipo de dados que eles revelam:
Campo
Informações Reveladas
Imports
Funções de outras bibliotecas que o malware utiliza.
Exports
Funções no malware que são projetadas para serem chamadas por outros programas ou bibliotecas.
Time Date Stamp
Data e hora em que o programa foi compilado.
Sections
Nomes das seções do arquivo e tamanhos, tanto no disco quanto na memória.
Subsystem
Indica se o programa é uma aplicação de linha de comando ou GUI.
Resources
Contém strings, ícones, menus e outras informações incluídas no arquivo.
Atualizado