12 de julho de 2012

Debugging como técnica de análise estática de malwares


Aproveitando o webcast realizado ontem à noite sobre Análise de Malwares como Técnica de Forense, resolvi escrever esse pequeno texto sobre um assunto que surgiu ao final.

Havia um “participante”, Raquere, que desde o início o intuito do mesmo estava claro, mas não vou entrar nesses pormenores... Mas surge sempre a dúvida: se a pessoa já sabe de tudo, porque participar de eventos, palestras, apresentações e etc? Ela não precisa disso, basta sentar numa cadeira, e esperar morrer :-)

Mas vamos lá... Esse Raquere (que deve ser um “raquere” l33t0 do mal, membro da Liga da Estrela da Morte), fez uma pergunta sobre debugging ser análise dinâmica ou estática. E como sempre, procurei ser bem claro, pois sei que pessoas com limitações cognitivas tem dificuldade de entendimento e aprendizado, mesmo que desenhemos bonecos de pauzinhos conversando entre si para explicar um conceito.

Minha explicação basicamente foi a seguinte:

“Em um caso onde temos um malware com packer, precisamos debuggar o código, descobrindo onde está o tail jump no unpacking stub, para aí colocarmos um breaking point, avançarmos com um step into e paramos o processo assim que o debugger atingir a primeira instrução do código do malware em si, antes de executá-lo. Sendo assim, nesse momento já teremos o malware desempacotado na memória física e podemos fazer um dump do mesmo, usando ferramentas específicas para isso, e prosseguirmos com a análise estática com o código desencriptado.”

Infelizmente achei que através dessa explicação, ficaria claro que debugging é uma técnica parta análise estática em processos de unpacking do malware, apenas nesse contexto,pois era disso que estava falando. Mas o Raquere, coitado, não entendeu. Vou ficar inclusive devendo um desenho, pois não sou tão bom desenhista assim :-)

Debugging é técnica de análise dinâmica quando executamos o código do malware, o que não é feito nos passos que expliquei acima. Esse é meu entendimento. Meu conceito pode até estar errado, mas a explicação acima não tem nada de errado.

Agora, para quem tem um pouco mais de interesse de entender o que foi explicado acima, vamos prosseguir. Para os demais, não vale a pena prosseguir, pois não vou mostrar telas do IDA Pro...

Malwares, em sua maioria das vezes, possuem proteções contra sua análise e acesso ao código fonte. E essas proteções muitas vezes são utilizadas em camadas.

As mais comumente encontradas são:
- Packer
- Crypter
- Anti-Debugging
- Anti-Disassembling
- Anti-VM

Vamos focar no primeiro tipo, packers.

Packers são ferramentas que permitem o empacotamento de executáveis, criptografando-os e comprimindo-os, o que permite deixá-los protegidos contra AV’s que trabalham com assinaturas, e dificultar a análise do código original do malware. Isso inclusive diminui sensivelmente a extração de strings a partir do PE analisado. Basta compararmos quantas strings conseguimos extrair de um PE normal e de seu equivalente “packeado”.

Então, como o malware consegue ser executado se está encriptado e compactado? Ao ser chamado, o packer desempacota o malware, jogando-o na memória, já desencriptado, e passa o controle de execução para código do malware através do OEP (Original Entry Point).

Mas porque isso acontece?

Porque quando o packer é executado em cima do malware para empacotá-lo, um novo PE é criado, para armazenar o PE original, com o acréscimo de mais um código em uma seção que chamamos de unpacking stub, que é o código para desempacotá-lo quando o mesmo é chamado. Ao final desse unpacking stub, temos o tail jump, que é uma função jmp (algumas vezes ret ou call, quando os desenvolvedores querem esconder a localização do tail jump), que direciona o ponteiro de execução para o endereço da memória onde está o OEP, para que o malware, já desempacotado, possa ser executado na memória onde já está localizado nesse momento.

Quando é utilizado um packer, passa a existir o EP e o OEP, onde o EP está apontando para o unpacking stub e o OEP para o ponto inicial do código original do malware (original entre aspas, porque depois de empacotado, após extraí-lo, se compararmos com o PE original, podemos perceber que sua estrutura foi alterada).

Logo abaixo temos um exemplo de identificação de packer utilizado, através do PEiD:



E abaixo, temos um gráfico que explica como funciona o processo de packing e unpacking:



Logo, quando utilizamos um debugging para executar apenas o código do unpacking stub, para descobrir o OEP e podermos realizar o dump da memória, recuperando o código original do malware, estamos executando o malware?

Será que quando, mesmo em um processo de debugging, e apenas nesse contexto, executamos apenas o unpacking stub para recuperar seu código, sem executar o código do malware, estamos realizando um processo de análise dinâmica, ou estática?

Depois que realizamos o dump da memória, com o malware desempacotado, podemos prosseguir com o processo de análise estática, extraindo strings e analisando as chamadas que faz à API e syscalls. O grande problema, é que quando fazemos isso, normamente a IAT (Importa Address Table) não é recuperada, então há a necessidade de recriá-la. Aí entramos na necessidade de uma análise dinâmica, onde executamos o malware (ainda empacotado), para remontar a IAT e fazer um fix no dump realizado anteriormente a partir da memória fixa.

Uma das ferramentas que permite essa recuperação da IAT, é o ImpREC. E para o dump da memória física, podemos usar o LordPE ou o plugin do OllyDBG, OllyDump.

Resumindo: debugging quando na execução do código do malware, é utilizado em análises dinâmicas. Entretanto, debugging como técnica de execução apenas do unpacking stub, sem executar o malware em si (será que tem alguém que considera o unpacking stub, do packer, como código do malware?), é uma técnica como parte de um processo de análise estática.

Um comentário:

  1. Cara, epero um dia entender disto pois no momento estou mais por fora do que bunda de índio :-D

    ResponderExcluir