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.
Cara, epero um dia entender disto pois no momento estou mais por fora do que bunda de índio :-D
ResponderExcluir