Skip to main content

Malware Analysis



Introdução a Análise de Malwares


O foco dessa introdução é te dar uma base sólida sobre o que é esse tipo de análise, por que ela é importante, e como ela é feita de forma segura. Primeiro, é essencial entender o que é um malware. Basicamente, é qualquer software desenvolvido com a intenção de causar dano, roubar informações, interromper serviços ou comprometer a integridade de sistemas. Isso inclui vírus, trojans, ransomwares, worms, e por aí vai. Esses códigos podem ser usados por cibercriminosos, grupos de espionagem ou até por governos, e estão cada vez mais sofisticados.


O papel da análise de malware é entender como essas ameaças funcionam, como se espalham, o que fazem quando são executadas e quais técnicas usam para evitar detecção. Pra isso, a gente divide a análise em dois tipos principais: estática e dinâmica.


Na análise estática, a gente não executa o malware. Em vez disso, analisamos o arquivo diretamente, observando strings, estrutura do código, bibliotecas usadas, e outras características do binário. Isso já pode revelar muita coisa: comandos ocultos, endereços de servidores de controle, nomes de arquivos que o malware cria, etc.


Já na análise dinâmica, a gente roda o malware, mas sempre em um ambiente seguro e isolado, como uma máquina virtual, e observa o que ele faz em tempo real. Isso inclui coisas como tentativas de conexão com a internet, criação de arquivos, modificações no registro do Windows, injeção de código em processos, entre outras atividades. Aqui é onde a gente realmente vê o comportamento malicioso em ação.


Um ponto crucial, esse tipo de análise nunca deve ser feito em um ambiente de produção ou conectado diretamente à internet real. Todo o trabalho precisa ser feito em um ambiente controlado, configurado especificamente para isso, com snapshots prontos para restaurar o sistema e ferramentas de monitoramento rodando o tempo todo.


O REMnux é uma distribuição Linux especializada em análise de malwares e engenharia reversa, ideal para ambientes de pós-exploração e testes de segurança. Ela já inclui diversas ferramentas essenciais, como Wireshark, radare2, YARA e Volatility, poupando o tempo de instalação e configuração.


A forma mais prática de usar o REMnux é baixando a máquina virtual no formato OVA pelo site oficial, que pode ser importado diretamente em VirtualBox, VMware ou Hyper-V. Se preferir, você também pode instalar o conjunto de ferramentas diretamente em uma instalação Ubuntu compatível, usando o instalador oficial.



Sistemas de Numeração


Antes de entender como o computador armazena e processa dados, é essencial compreender os sistemas de numeração, que são maneiras diferentes de representar valores. No nosso dia a dia, usamos o sistema decimal, que é baseado em 10 símbolos: de 0 a 9. Cada posição de um número decimal representa uma potência de 10, por isso temos unidades, dezenas, centenas, e assim por diante.


Mas o computador funciona de forma diferente. Ele não "entende" 10 símbolos, apenas dois estados físicos: ligado e desligado. Por isso, toda a base da computação é construída sobre o sistema binário, que só usa os dígitos 0 e 1. Cada 0 ou 1 é chamado de bit, e agrupamentos de bits são usados para representar qualquer tipo de dado: texto, imagem, som, etc.


Só que ler uma sequência longa de bits, como 101011001011, pode ser confuso para humanos. Para facilitar a leitura e o trabalho com binários, usamos o sistema hexadecimal. Ele é baseado em 16 símbolos: os números de 0 a 9, e as letras A até F (sendo A=10, B=11, até F=15). A grande vantagem do hexadecimal é que cada dígito representa exatamente 4 bits. Ou seja, dois dígitos hexadecimais equivalem a um byte (8 bits), o que simplifica muito a leitura de dados binários.


Por isso, o hexadecimal aparece o tempo todo na computação: endereços de memória, valores de cores em programação gráfica, instruções em linguagem de máquina, tudo é representado em hexadecimal porque ele condensa os dados binários de forma compacta e legível.



Tabela ASCII


A gente sabe que os computadores só trabalham com números binários. Mas quando você digita algo no teclado, uma letra, um número ou um símbolo, o que o computador realmente armazena e processa não é o caractere em si, mas um número correspondente a ele.


Para padronizar essa correspondência entre caracteres visíveis e códigos numéricos, foi criada na década de 60 a tabela ASCII, que significa American Standard Code for Information Interchange. A ideia era criar uma forma universal de representar texto que tanto máquinas quanto humanos pudessem entender e processar.


O padrão ASCII usa códigos de 7 bits, o que permite representar 128 valores (de 0 a 127). Cada um desses valores está associado a um caractere. Por exemplo:

  • O caractere A tem o valor decimal 65, o binário 0b1000001, e o hexadecimal 0x41.
  • Já o a minúsculo tem valor decimal 97, binário 0b1100001, e hexadecimal 0x61.

Além das letras, números e símbolos visíveis (como #, $, @), a tabela ASCII também inclui caracteres de controle, como \n (quebra de linha), \r (retorno de carro), \t (tabulação), entre outros. Esses não aparecem na tela, mas são essenciais para controlar o comportamento de texto e comunicação entre sistemas.


Sempre que você vê um caractere sendo exibido em um programa, no fundo, o que está ali é só um número armazenado na memória, que o sistema interpreta com base na tabela ASCII para exibir o símbolo correspondente. Por isso essa tabela é tão fundamental para tudo que envolve manipulação de texto em baixo nível, seja na programação, seja na análise de arquivos binários.



Arquivos


Um arquivo nada mais é do que uma sequência de dados armazenada em um dispositivo, organizada dentro de um sistema de arquivos para que possa ser manipulado: lido, salvo, alterado, movido, etc. Só que a gente está acostumado a identificar arquivos pelas extensões, como .txt, .pdf, .docx, .exe, e isso pode ser enganoso, porque um arquivo pode ter sua extensão trocada propositalmente para esconder sua natureza real.


Por isso, no Linux, usamos três comandos fundamentais para descobrir o que um arquivo realmente é:

  1. file

    Esse comando analisa o conteúdo interno do arquivo e identifica seu tipo real, com base em uma assinatura conhecida como Magic Number (ou Magic Bytes). Todo tipo de arquivo tem uma sequência inicial de bytes que o define, e o comando file consulta um banco chamado magic.mgc, geralmente localizado em /usr/lib/file/, que mapeia essas assinaturas.

  2. hd (ou hexdump)

    Serve para ver o conteúdo binário do arquivo de forma legível. Com o parâmetro -C, ele mostra o conteúdo em três colunas: o endereço em hexadecimal, os dados em hexadecimal e a visualização em ASCII. Isso é essencial para perceber padrões, strings suspeitas ou até dados ocultos que não aparecem quando você abre o arquivo normalmente.

  3. stat

    Esse comando exibe informações de metadados do arquivo, como quando ele foi criado, modificado, acessado pela última vez, quem é o dono, quais são as permissões, entre outras informações que ajudam a rastrear a origem e comportamento do arquivo.


Esse tipo de abordagem é fundamental em análise estática de malware, porque nos permite estudar o comportamento e estrutura de arquivos potencialmente maliciosos sem executá-los, o que reduz riscos e oferece controle total da análise.



Conceitos da Análise de malware


A análise de malware é uma atividade fundamental dentro da cibersegurança e envolve o estudo de softwares maliciosos com o objetivo de entender seu funcionamento, identificar suas capacidades e mitigar seus impactos. Existem dois principais tipos de análise: estática e dinâmica.


A análise estática examina o malware sem executá-lo. Ela pode ser básica, utilizando técnicas como extração de hashes, strings e análise da estrutura do binário, ou avançada, que envolve engenharia reversa do código para entender sua lógica de funcionamento. A vantagem da análise estática é a segurança, pois não envolve a execução do malware, e, muitas vezes, ela já é suficiente para identificar as intenções do código malicioso.


Já a análise dinâmica executa o malware em um ambiente controlado, como uma máquina virtual ou sandbox, para observar seu comportamento em tempo real. Ela também pode ser básica, apenas monitorando alterações em arquivos, rede e processos, ou avançada, com o uso de debuggers para examinar a execução passo a passo. Essa abordagem é útil quando o malware usa técnicas de ofuscação ou empacotamento que dificultam a análise estática.


Durante a análise, é comum encontrar malwares que usam técnicas para evitar a detecção ou dificultar a engenharia reversa, como anti-debugging, anti-VM e uso de packers. Por isso, o analista deve conhecer bem arquitetura de computadores, opcodes, registradores e engenharia de software.


Além disso, o uso de máquinas virtuais é recomendado para garantir a segurança do analista e preservar o sistema host, já que é possível criar snapshots e retornar a estados anteriores caso algo dê errado.



Engenharia de Software


Dentro do contexto da análise de malware, a engenharia de software é essencial porque fornece os fundamentos para entender como programas são estruturados, desenvolvidos e executados. Isso é particularmente importante quando se está lidando com malwares complexos, que podem ser escritos em linguagens de baixo ou alto nível, muitas vezes com técnicas sofisticadas de ocultação e evasão.


A arquitetura de computadores é dividida em diferentes níveis por meio da abstração, criando camadas que executam conjuntos específicos de instruções e se interligam. Essas camadas são:


A Camada 0, de lógica digital, corresponde ao hardware físico que realiza operações básicas com sinais elétricos. A Camada 1, de controle, coordena a execução de instruções nesses circuitos. A partir da Camada 2, temos a Arquitetura de Conjunto de Instruções (ISA), que define o conjunto de instruções que o processador é capaz de executar.


Na Camada 3 entra o sistema operacional, que abstrai o hardware e fornece recursos como gerenciamento de processos, memória e dispositivos. Isso é crucial na análise de malware, pois é nessa camada que o malware geralmente interage com o sistema – criando arquivos, conectando à rede, ou injetando código em processos legítimos.


Na Camada 4, a linguagem de montagem traduz as instruções de alto nível em comandos mais próximos da linguagem de máquina, permitindo controle mais direto sobre o hardware. Essa camada é especialmente importante em engenharia reversa, quando o analista examina o código em assembly para descobrir o que o malware está fazendo.


As Camadas 5 e 6 representam, respectivamente, as linguagens de programação de alto nível e os aplicativos que o usuário executa. Malwares modernos muitas vezes são desenvolvidos em linguagens de alto nível e depois compilados para binários, o que significa que a análise pode precisar "voltar" por essas camadas para entender o comportamento do software.


Essa organização em camadas facilita tanto o desenvolvimento quanto a análise de sistemas, permitindo que os analistas de malware se concentrem na camada adequada dependendo do tipo de análise (estática ou dinâmica) e do nível de obfuscação ou complexidade do código malicioso.



Arquitetura de Von Neumann


A arquitetura de Von Neumann é a base da maioria dos computadores atuais e representa um modelo lógico em que instruções de programa e dados compartilham o mesmo espaço de memória. Isso permite que os computadores sejam programáveis de forma flexível, já que qualquer parte da memória pode conter dados ou instruções, dependendo do contexto.


No contexto da análise de malware, entender essa arquitetura é essencial porque ela define como o malware interage com o sistema. A CPU executa as instruções maliciosas; a memória armazena tanto o código do malware quanto os dados manipulados por ele (como payloads criptografados ou informações coletadas da máquina infectada); e o barramento é o meio por onde essas informações transitam entre os componentes.


A unidade de controle tem papel fundamental nesse processo, já que ela determina a ordem de execução das instruções, que pode ser manipulada por técnicas como jumps e chamadas indiretas, comuns em códigos maliciosos para mascarar sua lógica. Além disso, o fato de instruções e dados estarem na mesma memória permite que o malware altere seu próprio código durante a execução, técnica conhecida como self-modifying code, muito utilizada para evasão de antivírus e ofuscação.


Essa compreensão permite ao analista mapear com mais precisão as interações entre o malware e o sistema, além de prever possíveis formas de comportamento malicioso com base em como a arquitetura executa os programas.



Arquitetura Intel x86


A arquitetura Intel x86, também chamada IA-32, é extremamente relevante para a análise de malware porque a maioria dos malwares que circula atualmente ainda é desenvolvida para essa plataforma. Ela define um conjunto específico de instruções, registradores e modos de operação com os quais o malware vai interagir diretamente.


Essa arquitetura utiliza registradores como EAX, EBX, ECX, EDX, entre outros, que são frequentemente analisados durante engenharia reversa para entender a lógica do malware. Além disso, a compatibilidade da arquitetura x86 com sistemas operacionais modernos de 64 bits (como AMD64 e IA-64) permite que malwares de 32 bits ainda sejam executados sem problemas, o que explica sua persistência.


Do ponto de vista estratégico, a predominância do sistema operacional Windows (responsável por cerca de 77% das instalações em desktops e notebooks) torna esse ambiente o principal alvo dos criadores de malware. Isso influencia tanto o vetor de ataque quanto a escolha das técnicas usadas, como injeção de código em processos do Windows, uso de APIs específicas do sistema, ou exploração de falhas conhecidas em suas bibliotecas.




Registradores


Na arquitetura x86, que é amplamente usada em processadores da Intel e AMD, existem registradores fundamentais que atuam como pequenos espaços de armazenamento dentro do processador, cada um com uma função bem definida.


Os registradores de uso geral (como EAX, EBX, ECX e EDX) servem para guardar valores temporários e realizar cálculos. O EAX, por exemplo, costuma guardar o resultado de funções. O EBX geralmente serve como uma base para endereçar dados na memória. O ECX e o EDX são bastante usados para contar repetições em laços ou segurar dados temporários durante uma operação.


O ESP é o registrador que aponta para o topo da pilha de memória. Ele é fundamental para organizar chamadas de função, armazenar variáveis locais e controlar o que entra e sai da pilha. Já o EBP também lida com a pilha, mas ele é mais usado para acessar dados estáticos como parâmetros de função ou variáveis locais de forma mais estruturada.


Temos também o ESI e o EDI, que são registradores voltados para operações com strings e cópia de dados. O ESI guarda o endereço de onde os dados estão saindo, e o EDI, para onde eles devem ir.


Por fim, o EFLAGS armazena informações sobre o estado atual do processador, como se o resultado de uma operação foi zero, se houve estouro numérico, se um número é negativo, entre outras condições. Esses indicadores são muito importantes para decisões de fluxo no código, como saltos condicionais.


Além desses, há outros registradores como os de segmento, que ajudam no controle de memória e na segurança da execução dos programas. Cada registrador tem uma função bem definida no processo de execução das instruções dentro do processador x86.



EIP


Imagina que você está olhando o funcionamento interno de um programa que está rodando no seu computador. O processador, que é como o "cérebro" da máquina, precisa saber exatamente qual instrução executar a cada momento. É aí que entra o EIP, o ponteiro de instrução estendido. Ele é um registrador da arquitetura x86 e funciona como um marcador que aponta para o próximo comando (ou instrução) que o processador vai executar na memória. Esse valor não pode ser qualquer um, precisa ser um endereço válido na memória, senão o programa pode travar ou causar uma falha de segmentação.



OPCODES


Agora, quando você está analisando um malware ou qualquer programa compilado, o que o processador executa de fato são os opcodes, que são códigos binários específicos representando instruções como "mover um valor", "somar dois números", "pular para outra parte do código", entre outros. Cada um desses códigos tem um significado exato para a CPU.


Esses opcodes são resultado da compilação de um programa escrito em uma linguagem de alto nível (como C ou Python) para linguagem de máquina. Quando você usa um disassembler, como o IDA ou o Ghidra, ele pega esse código de máquina, normalmente visualizado em hexadecimal, já que dois dígitos hexadecimais representam um byte, e transforma em código assembly, que é mais legível para humanos. Por exemplo, o opcode B8 01 00 00 00 em hexadecimal corresponde à instrução MOV EAX, 1 em assembly, que significa colocar o número 1 no registrador EAX.


Os operandos são os dados com os quais essas instruções trabalham. Eles podem ser valores fixos (como 0x04), registradores (como EAX, EBX), ou endereços de memória (como [EAX+0x16]). Entender como esses elementos se combinam é essencial para analisar como um malware age, especialmente em uma análise estática, onde você não executa o código e precisa deduzir seu comportamento só observando as instruções.



Engenharia reversa


Engenharia reversa, no contexto de análise de malware, é como pegar um quebra-cabeça já montado e tentar descobrir como ele foi construído peça por peça, sem ter a imagem original de referência. Você parte de um arquivo compilado, normalmente um executável, e tenta reconstruir o raciocínio que o desenvolvedor (nesse caso, o criador do malware) usou para programá-lo.


Como esses arquivos executáveis já estão em formato binário, ou seja, traduzidos para a linguagem de máquina que o processador entende, o primeiro passo da engenharia reversa é usar um disassembler. Esse software converte os bytes do binário em instruções legíveis em linguagem assembly, que é uma representação textual de baixo nível do que a CPU executa.


Por exemplo, um trecho binário pode ser traduzido para MOV EAX, 1, o que indica que o valor 1 será colocado no registrador EAX. A partir dessas instruções, o analista começa a entender o que o programa faz: se ele tenta se conectar à internet, alterar arquivos do sistema, capturar dados do usuário, entre outros comportamentos.


Esse processo exige bastante conhecimento técnico, especialmente em arquitetura de computadores, sistemas operacionais, estruturas de arquivos executáveis e principalmente programação em C e assembly. É uma forma de "ler" o software de trás para frente, sem acesso ao código-fonte original, apenas ao que a máquina entende para rodar. Essa habilidade é fundamental para quem trabalha com segurança ofensiva ou defesa contra ameaças digitais.



Técnicas de Proteção do Código


Os criadores de malware sabem que seus códigos podem ser analisados e bloqueados por antivírus, IDS (sistemas de detecção de intrusão) e IPS (sistemas de prevenção de intrusão). Por isso, eles implementam técnicas para dificultar ou atrasar esse processo de detecção e análise, tentando fazer com que o malware passe despercebido ou, pelo menos, se mantenha ativo o maior tempo possível.


Uma técnica bastante comum é a ofuscação. Com ela, o código do malware é propositalmente embaralhado, mas ainda funcional. Isso pode ser feito trocando nomes de variáveis, inserindo instruções irrelevantes ou reorganizando a lógica do programa para dificultar a leitura por um analista ou uma ferramenta automática.


Outra técnica é o uso de empacotadores (packers), que comprimem ou criptografam o executável original, criando uma "casca" que só será desembrulhada em tempo de execução. Isso impede que ferramentas de análise estática vejam o conteúdo real do malware sem primeiro executá-lo.


Além disso, há técnicas como anti-debugging, que incluem rotinas dentro do malware para detectar se ele está sendo analisado por um depurador. Se detectar, pode mudar de comportamento, encerrar a execução ou executar uma ação destrutiva.


Também existe o anti-disassembly, onde o código é escrito de modo a confundir ou impedir a correta desmontagem por ferramentas como IDA Pro ou Ghidra. Isso pode envolver instruções inválidas ou saltos condicionais falsos que embaralham o fluxo lógico do código.


Por fim, os malwares podem usar técnicas anti-VM para verificar se estão rodando dentro de uma máquina virtual, ambiente comumente usado para análises seguras. Se detectarem isso, eles ficam inativos ou alteram seu comportamento.


Essas estratégias são constantemente aprimoradas pelos atacantes, obrigando os profissionais de segurança a se manterem atualizados e a desenvolverem contramedidas cada vez mais sofisticadas.



Polimorfismo


Polimorfismo em malware funciona como uma técnica de camuflagem. A ideia principal é evitar que os antivírus consigam identificar o malware com base em sua assinatura, que normalmente é um padrão fixo de bytes ou comportamentos registrados. O truque está em alterar a aparência externa do malware a cada vez que ele é executado ou copiado, mesmo que sua funcionalidade interna permaneça a mesma.


Isso é feito por meio da criptografia do corpo principal do código malicioso, que só é decodificado em tempo de execução. O malware contém um pequeno trecho de código fixo responsável por fazer essa decodificação, e é essa parte que o antivírus pode tentar identificar como assinatura. Mas o conteúdo principal, criptografado com chaves geradas aleatoriamente, muda completamente a cada instância.


Na prática, dois arquivos maliciosos polimórficos que fazem exatamente a mesma coisa podem ter aparências binárias completamente diferentes. Isso quebra a lógica tradicional de detecção por assinatura baseada em disco, que depende de encontrar padrões fixos.


Por conta disso, alguns antivírus passaram a inspecionar a memória do sistema, onde o malware já está decodificado e pronto para agir. Nessa fase, mesmo que o binário esteja diferente no disco, o comportamento do malware na memória é sempre o mesmo, e é isso que o antivírus tenta capturar e correlacionar com uma base de assinaturas de memória.


Outra abordagem útil é monitorar a presença do código de descriptografia, que por mais que atue sobre conteúdos diferentes, ele próprio não muda. Isso dá uma chance de detectar o malware antes que ele consiga se decodificar e executar seu código malicioso.



Metamorfismo


O metamorfismo leva a camuflagem de malwares a um nível ainda mais sofisticado do que o polimorfismo. Enquanto o polimorfismo altera apenas a forma como o código é armazenado e decodificado, mantendo um trecho fixo para descriptografar o conteúdo, o metamorfismo muda o próprio código executável em cada nova instância, inclusive as instruções que compõem o malware.


Imagine um vírus que, a cada vez que se copia, reescreve suas próprias instruções de maneira que continue fazendo a mesma coisa, mas usando caminhos diferentes. Ele pode, por exemplo, substituir uma instrução por outra equivalente, mudar a ordem de execuções sem alterar o resultado, embaralhar funções e até inserir comandos inúteis (os chamados "lixos") apenas para confundir desassembladores e dificultar a leitura do código.


Esse processo de regeneração é feito automaticamente por motores internos dentro do próprio malware, que analisam seu código e geram uma nova versão funcional, mas diferente na estrutura. Isso impossibilita a criação de uma assinatura fixa, já que não há padrão estático a ser reconhecido, nem mesmo em pequenos trechos do código.


Por isso, malwares metamórficos são especialmente difíceis de detectar por antivírus que dependem de assinaturas tradicionais. A detecção costuma exigir técnicas mais avançadas, como análise comportamental, monitoramento da atividade em tempo de execução ou até análise heurística, tentando identificar intenções maliciosas a partir do que o código faz, não de como ele parece.



Técnicas anti-engenharia reversa


As técnicas anti-engenharia reversa são um conjunto de estratégias empregadas pelos criadores de malware para proteger seu código contra análise e desmonte. O objetivo principal dessas técnicas é aumentar ao máximo a dificuldade e o tempo necessário para que um analista entenda como o malware funciona, atrasando ou até impedindo a criação de contramedidas eficazes.


Uma das técnicas mais comuns é o uso de anti-debugging, que consiste em rotinas inseridas no malware para detectar se ele está sendo executado sob um depurador como OllyDbg ou x64dbg. Quando isso é detectado, o malware pode mudar de comportamento, travar ou até executar ações destrutivas, enganando o analista.


Outra abordagem bastante usada é o anti-disassembly, em que o código é escrito de forma a enganar ferramentas como IDA Pro. Isso pode envolver o uso de saltos falsos, instruções inválidas propositalmente ou até blocos de código embaralhados, dificultando a reconstrução lógica do fluxo do programa.


Malwares também podem empregar técnicas anti-VM, detectando se estão sendo executados em uma máquina virtual, o que é muito comum durante análises de segurança. Quando percebem esse ambiente, eles simplesmente não executam seu comportamento malicioso, fazendo parecer que são inofensivos.


Além disso, existe a manipulação de APIs do sistema operacional para ocultar processos, arquivos, conexões de rede e outras atividades, o que torna a análise comportamental mais complicada.


Todas essas estratégias não impedem a engenharia reversa, mas aumentam significativamente o tempo e o esforço necessário para que ela seja realizada. E em segurança da informação, tempo é um recurso crítico, quanto mais difícil for entender um malware, mais ele pode agir sem ser interrompido.



Técnica anti-virtual-machine


A técnica anti-virtual-machine (anti-VM) é uma das defesas mais eficazes usadas por malwares para evitar análise. Como grande parte dos analistas trabalha em ambientes virtuais isolados, justamente para evitar danos ao sistema principal, o malware tenta detectar esses sinais de que está sendo vigiado. Se detectar, muda seu comportamento, se desativa ou até se apaga.


Isso é possível porque ambientes virtuais deixam rastros, como drivers específicos do VirtualBox ou VMware, chaves de registro que indicam a instalação desses ambientes, processos típicos de máquinas virtuais em execução e até padrões de hardware como endereços MAC com prefixos conhecidos. Além disso, tarefas que envolvem chamadas ao clock do sistema ou operações de disco podem ser mais lentas ou inconsistentes numa VM, o que também pode ser um indício.


Para enganar esses malwares e conseguir analisá-los, o analista pode tomar algumas medidas. Uma delas é modificar ou apagar entradas no Registro do Windows que entregam a presença da máquina virtual ou dos softwares de monitoramento. Outra é alterar o MAC address da placa de rede virtual, usando endereços que não revelem a origem virtualizada. E há ainda truques mais sutis, como conectar uma impressora virtual à máquina, um artifício porque malwares geralmente supõem que VMs não tenham periféricos conectados.


Essas alterações não garantem que o malware não detectará o ambiente virtual, mas reduzem bastante as chances. O objetivo é justamente criar um cenário convincente o suficiente para que o código malicioso se comporte como se estivesse num sistema real, facilitando a análise e a coleta de informações sobre seu funcionamento.



Técnicas de anti-debugging


Técnicas de anti-debugging são como armadilhas plantadas dentro do malware para identificar se ele está sendo analisado com ferramentas de depuração, como OllyDbg, x64dbg ou WinDbg. O objetivo dessas técnicas é dificultar ao máximo a vida do analista, impedindo que ele acompanhe a execução passo a passo ou visualize as estruturas internas do código.


A forma mais comum de implementar isso é através de APIs nativas do sistema operacional. No Windows, por exemplo, o malware pode chamar IsDebuggerPresent() para verificar se está rodando sob depuração. Se a resposta for positiva, ele pode reagir imediatamente, se autoencerrando, apagando parte de seu código ou se modificando para dificultar ainda mais a análise.


Além disso, há técnicas mais elaboradas, como verificação de interrupções, checagem de flags no registrador EFLAGS (como o bit de trap flag, que indica execução passo a passo), ou ainda a leitura direta de estruturas internas do sistema operacional que revelam a presença de um debugger.

Alguns malwares também tentam manipular ou corromper os próprios debuggers. Isso pode ser feito, por exemplo, suspendendo o processo da ferramenta, alterando arquivos de log ou inserindo instruções ilegais que causem falhas na depuração.


O analista precisa ficar atento a esses comportamentos. Quando se percebe que o malware age de forma estranha (executa por um segundo e para, ou entra num loop sem sentido) pode ser sinal de anti-debugging ativo. Nessas situações, é comum recorrer a técnicas para mascarar o debugger, alterar manualmente a resposta de APIs como IsDebuggerPresent ou até usar máquinas físicas e técnicas de monitoramento em nível mais baixo, como engenharia reversa em modo kernel.



Ofuscação


A ofuscação, quando aplicada a malwares, tem como principal função esconder a verdadeira intenção do código até o momento da execução. Um dos métodos mais utilizados para isso são os packers, que são programas ou rotinas que empacotam (ou compactam) o código malicioso. O resultado é um executável que, à primeira vista, parece inofensivo ou ilegível, e que só revela sua carga maliciosa real após ser carregado na memória.


Esse processo funciona assim, o código original do malware é transformado e comprimido, e um pequeno loader é incluído no início do executável. Esse loader é responsável por, em tempo de execução, descompactar ou decodificar o conteúdo e então transferir o controle para o código real do malware.


Essa abordagem é eficaz contra a análise estática porque, ao abrir o binário com ferramentas como IDA ou Ghidra, o analista verá principalmente o código do loader, e não o código malicioso em si. Isso complica ou até impede a leitura direta do comportamento do malware sem executá-lo.


Além disso, existem packers comerciais e de uso genérico (como UPX), mas muitos malwares usam packers customizados para evitar detecção, especialmente porque ferramentas de segurança conseguem, em alguns casos, desembrulhar automaticamente packers conhecidos.


Para analisar um malware ofuscado por packers, muitas vezes é necessário partir para a análise dinâmica, executando o código em um ambiente controlado e monitorando o processo de desembrulhamento. Com técnicas como dumping da memória, é possível extrair o código já decodificado e, aí sim, seguir com a análise tradicional.



Análise Estática


Na análise estática de malwares, o primeiro passo sempre envolve o levantamento de contexto. Saber onde e como o arquivo foi obtido, qual era o ambiente (sistema operacional, perfil do usuário, nível de privilégio, rede) e que tipo de comportamento suspeito foi observado antes da coleta é fundamental. Essas informações ajudam a guiar o analista durante todo o processo, pois cada detalhe pode revelar o tipo de ameaça e quais técnicas podem ter sido utilizadas.


O princípio básico da análise estática é: não executar o malware em hipótese alguma nesse estágio. Tudo que será descoberto vem da inspeção direta do binário, ou seja, do arquivo tal como foi recebido. Com isso, evita-se qualquer risco de execução acidental e de propagação do código malicioso.


As primeiras técnicas aplicadas incluem o cálculo de hashes como MD5, SHA1 ou SHA256. Esses identificadores únicos são usados para verificar se o artefato já é conhecido em bases públicas, como VirusTotal, e também para documentar a análise. Depois, analisam-se as strings, fragmentos de texto presentes no binário, que podem indicar nomes de arquivos, URLs, comandos de shell ou até mensagens internas do código.


Em seguida, é feita a análise da estrutura do arquivo, principalmente se for um executável PE (Portable Executable) no caso de Windows. Isso envolve verificar seções como .text, .data, .rdata, entre outras, que podem indicar onde está o código, os dados e as referências externas.


Por fim, examinam-se as chamadas de funções da API do sistema operacional. Essas chamadas revelam muito sobre o comportamento do malware: se ele tenta abrir conexões de rede, modificar arquivos do sistema, interagir com o registro do Windows ou acessar informações sensíveis. Ferramentas como PEiD, Exeinfo PE, DIE (Detect It Easy), strings, e IDA Pro são muito usadas para essa fase.


Com essas análises, muitas vezes já é possível concluir se o artefato é um malware conhecido, especialmente se ele não estiver ofuscado ou compactado. A correspondência com assinaturas conhecidas, guardadas por empresas de segurança, é um recurso valioso nesse momento, pois permite identificar amostras reincidentes ou variantes de ameaças anteriores.



Função Hash


A função hash é como uma impressão digital do arquivo, ela transforma qualquer quantidade de dados, seja um pequeno script ou um executável de gigabytes, em uma sequência fixa de caracteres, como um código hexadecimal de 32 ou 64 dígitos. Essa transformação é feita de forma unidirecional, ou seja, não é possível reverter o hash e obter o conteúdo original a partir dele.


Na prática, o hash serve para verificar a integridade de arquivos e, no caso da análise de malware, para identificar exatamente qual é o artefato em questão. Se você calcular o hash de um malware e ele for igual ao hash publicado por outro analista ou presente em uma base de dados pública como VirusTotal, você pode afirmar com segurança que está analisando o mesmo binário.


Isso é útil por diversos motivos. Primeiro, evita trabalho duplicado, pois se alguém já analisou o malware, você pode usar essas informações como referência. Segundo, é uma forma confiável de catalogar e compartilhar amostras, já que qualquer alteração mínima no arquivo (mesmo que seja apenas um ponto a mais no final de um texto) gera um hash completamente diferente.


Embora o MD5 ainda seja amplamente usado por causa da velocidade e ampla compatibilidade, ele já foi considerado inseguro por permitir colisões, situações em que dois arquivos diferentes produzem o mesmo hash. Por isso, em ambientes mais críticos ou onde há exigência de maior segurança, utiliza-se SHA-1 ou, preferencialmente, SHA-256.


Durante a análise estática, uma das primeiras tarefas do analista é calcular os hashes do arquivo com ferramentas como md5sum, sha256sum ou utilitários gráficos como HashCalc. Depois disso, ele busca esses valores em bancos de dados de ameaças para identificar a amostra e, se possível, acelerar a análise com dados já conhecidos.



Imphash


O imphash é uma técnica muito útil na análise de malwares porque vai além do conteúdo binário puro, ele foca na estrutura de importações do executável, ou seja, nas bibliotecas do sistema que o malware utiliza e na ordem dessas chamadas. Isso permite identificar amostras que foram ligeiramente modificadas para evitar detecção, mas que continuam usando a mesma base de código ou o mesmo conjunto de funções.


Quando um executável Windows é analisado, ele geralmente carrega DLLs padrão como kernel32.dll, user32.dll, advapi32.dll, entre outras, que oferecem acesso às funcionalidades do sistema operacional. O malware, ao ser compilado, define exatamente quais funções dessas bibliotecas vai utilizar. A ordem e o nome dessas funções são registrados na tabela de importação do arquivo PE (Portable Executable).


A partir dessa tabela, constrói-se uma string no seguinte formato: o nome da biblioteca (sem a extensão .dll) seguido por um ponto e o nome da função, repetido para cada função, separado por vírgulas. Essa string é convertida para minúsculas e transformada num hash (geralmente MD5) que é o imphash.


Essa abordagem é muito poderosa porque dois malwares que foram recompilados com pequenas modificações (por exemplo, mudança de nome de variável ou inserção de código lixo) ainda podem ter o mesmo imphash se as funções importadas forem idênticas e estiverem na mesma ordem. Isso permite que ferramentas e analistas consigam agrupar famílias de malware com base na forma como interagem com o sistema operacional, mesmo que os arquivos em si não sejam binariamente idênticos.


Por isso, durante uma análise estática, calcular o imphash do arquivo é uma maneira eficaz de identificar variantes de malwares conhecidos e encontrar relações entre diferentes amostras. Ele é especialmente valioso em bancos de dados que agrupam amostras por comportamento, não só por assinatura binária.



VirusTotal


O VirusTotal é uma das ferramentas mais valiosas para quem trabalha com análise de malware, justamente porque centraliza o uso de dezenas de motores antivírus em uma única análise. Quando você envia um arquivo suspeito, o serviço o escaneia usando aproximadamente 70 antivírus diferentes, além de realizar análises comportamentais, verificar conexões de rede associadas e até fornecer informações sobre a estrutura do arquivo, como metadados e hashes.


Esse processo pode ser iniciado diretamente no site oficial, com o envio manual do arquivo, mas também pode ser feito por meio de aplicações para desktop ou scripts automatizados, usando a API pública ou privada do serviço. A API, aliás, é bem robusta e tem suporte a várias linguagens, o que permite integrar o VirusTotal em pipelines de segurança ou ferramentas próprias de análise.


Além da análise de arquivos, o VirusTotal também aceita URLs, domínios e endereços IP, verificando sua reputação com base em diversas blacklists e motores de reputação. Isso é útil para identificar sites de phishing, servidores de comando e controle (C2) ou domínios associados a campanhas de malware.


Um ponto importante é que tudo que for enviado ao VirusTotal é armazenado e compartilhado com a comunidade de segurança. Isso é ótimo para analistas, pois cria um histórico consultável de ameaças. No entanto, do ponto de vista do atacante, enviar um malware ao VirusTotal para ver se é detectado pode ser um tiro no pé: ele acabará expondo seu código à comunidade, permitindo que ele seja rapidamente detectado por outros analistas e softwares de proteção.


Por isso, muitos criadores de malware testam seus códigos em ambientes isolados, sem conexão com serviços como o VirusTotal, justamente para evitar gerar alertas e deixar rastros visíveis na rede de segurança.



PEID


O PEiD é uma ferramenta antiga, mas ainda bastante útil no contexto da análise estática de malwares. Sua principal função é identificar, com base em assinaturas conhecidas, se um executável do tipo PE foi empacotado, criptografado ou compilado com ferramentas específicas. Isso é essencial porque muitos malwares usam packers ou cryptors para esconder sua real estrutura, dificultando a análise direta do código.


Ele trabalha escaneando as seções e os padrões de código do executável e comparando com uma base de mais de 600 assinaturas. Se encontrar uma correspondência, o PEiD informa qual packer, cryptor ou compilador foi utilizado. Com isso, o analista pode tomar decisões importantes: por exemplo, se for um packer conhecido como UPX, pode usar um unpaker para extrair o conteúdo original antes de iniciar a engenharia reversa.


Apesar de estar descontinuado pelos desenvolvedores, o PEiD ainda é amplamente utilizado e pode ser encontrado em sites de repositórios como o Softpedia. Ele continua relevante porque, mesmo com o surgimento de novas ferramentas, sua simplicidade e rapidez o tornam uma excelente primeira etapa de triagem para análise de executáveis suspeitos.



Pestudio


O pestudio é uma ferramenta muito valiosa para quem realiza análise estática de malware, especialmente na fase inicial de triagem de arquivos suspeitos. Ele permite examinar executáveis sem executá-los, o que garante uma análise segura e evita qualquer risco de infecção acidental durante o processo.


A principal vantagem do pestudio está na sua interface clara e na riqueza de informações que ele apresenta. Ele analisa o cabeçalho do arquivo PE, detecta anomalias estruturais, exibe todas as strings presentes, apresenta as bibliotecas e funções importadas e ainda faz verificações automáticas contra listas de indicadores maliciosos conhecidas. Tudo isso usando arquivos de configuração em XML, que podem ser atualizados e personalizados conforme a necessidade do analista.


Um recurso especialmente útil é a análise de reputação de APIs importadas. Se o arquivo estiver chamando funções potencialmente perigosas, como aquelas associadas a manipulação de memória, rede ou controle de processos, o pestudio destaca essas chamadas, ajudando o analista a identificar possíveis comportamentos maliciosos mesmo antes de olhar o código em detalhes.


Outro ponto positivo é que ele permite visualizar o imphash do arquivo, facilitando a correlação com outras amostras. E como o pestudio não executa o binário, ele é ideal para uma avaliação rápida e segura, podendo ser usado como primeira etapa antes de se decidir se vale a pena avançar para uma engenharia reversa mais profunda.


A versão gratuita já oferece uma gama significativa de funcionalidades e pode ser baixada diretamente do site oficial, winitor.com.



Análise Estática Avançada


A análise estática avançada se aprofunda nos detalhes de como o código funciona internamente, sem depender da execução. Diferente da análise básica, que busca por hashes, strings e chamadas de API, aqui o foco é entender a lógica do programa, investigando sua estrutura no nível da linguagem de máquina, e para isso, o conhecimento de arquitetura x86, assembly e funcionamento da pilha (stack) é essencial.


Toda vez que uma função é chamada em um programa, ela segue uma convenção, ou seja, uma forma padrão de passar parâmetros, guardar o endereço de retorno e alocar espaço para variáveis locais. No x86, isso geralmente envolve o uso dos registradores ESP (stack pointer) e EBP (base pointer). Quando uma função é chamada com a instrução CALL, o endereço de retorno (o ponto de onde o código deve continuar após a execução da função) é empilhado automaticamente.


Na sequência, o código dentro da função começa com o famoso prologue, normalmente algo como:

PUSH EBP
MOV EBP, ESP
SUB ESP, <tamanho>

Essas instruções servem para preservar o contexto anterior e criar um novo quadro de pilha para a função atual. Os parâmetros da função ficam logo acima do EBP na pilha, e podem ser acessados com instruções como MOV EAX, [EBP+8], onde EBP+8 aponta para o primeiro argumento passado.


Depois que a função termina seu trabalho, vem o epilogue, que desfaz as alterações:

MOV ESP, EBP
POP EBP
RET

Esse padrão se repete em praticamente todo código compilado com linguagens de alto nível como C ou C++, e entender essa estrutura é a chave para decifrar o que cada função maliciosa está realmente fazendo. Na engenharia reversa, identificar essas chamadas e seguir o fluxo entre elas permite mapear o comportamento completo do malware, mesmo sem rodar o executável.


Esse conhecimento é fundamental especialmente quando o malware está ofuscado, empacotado ou criptografado, e você precisa reconstruir o funcionamento apenas observando os opcodes e a manipulação da stack.



Função


Quando um software é executado, o sistema operacional carrega seu conteúdo do disco para a RAM e organiza esse conteúdo em diferentes regiões de memória: dados, código, heap e pilha (stack). A pilha é a área mais dinâmica e crítica para a execução de funções, principalmente em programas escritos em linguagens como C.


A função da stack é gerenciar chamadas de função, armazenar parâmetros, valores de retorno, endereços de retorno e variáveis locais. Ela funciona com a lógica LIFO: o último dado a entrar será o primeiro a sair. A cada nova função chamada, uma nova "pilha de ativação" é criada no topo da stack.


Dois registradores principais controlam esse processo na arquitetura x86, o ESP, que aponta para o topo da pilha (e muda constantemente com cada PUSH ou POP), e o EBP, que serve como referência fixa dentro da pilha para acessar os parâmetros e variáveis locais da função. Durante a execução, os parâmetros são empilhados primeiro, depois ocorre a chamada da função (CALL), que empilha o endereço de retorno. O prólogo da função então preserva o estado anterior e organiza o espaço para variáveis locais. Isso normalmente é feito assim:

PUSH EBP
MOV EBP, ESP
SUB ESP, <tamanho>

Durante a execução da função, os dados são acessados via EBP, por exemplo, EBP+8 pode apontar para o primeiro argumento, e EBP-4 para uma variável local. Ao final da função, o epílogo desfaz essas alterações com:

MOV ESP, EBP
POP EBP
RET

Essa estrutura se repete para cada chamada de função e é a base para entender não só a lógica de execução de programas legítimos, mas também como malwares manipulam a pilha para realizar suas ações. Muitos malwares abusam dessas estruturas para sobrescrever endereços de retorno, manipular variáveis de forma maliciosa ou desviar o fluxo de execução, por isso dominar essa mecânica é essencial na análise estática avançada.

Aula 4 - Análise Dinâmica