DLL, Dynamic Link Library, é a forma que o Windows utiliza para compartilhar bibliotecas de funções entre múltiplas aplicações. Internamente uma DLL é bem semelhante a um EXE, utiliza o formato PE e somente uma simples flag diferencia que é uma DLL e não um EXE (essa flag está no IMAGE_FILE_HEADER no campo Characteristics do PE Header). Além disso DLLs geralmente têm mais Exports que os executáveis.
DLL não é um arquivo standalone, se clicarmos duas vezes nela ela não vai executar, necessita de um processo host. Esse processo é o responsável por carregar a DLL para seu espaço de memória através da função LoadLibrary.
Assim como os executáveis, as DLLs também possuem seu entry point (é chamado de DllMain ou DllEntryPoint), que na teoria é o endereço da primeira instrução que será executada pela DLL assim que ela for carregada na memória do processo host. Assim que a LoadLibrary carrega uma DLL na memória, automaticamente ela executa a DllMain.
Para os malwares, as DLLs são ótimos lugares de armazenamento de códigos maliciosos, inclusive por sua análise ser um pouco mais complicada que a de um executável comum. Imagine uma DLL com um packer, se pretendemos retirar a proteção através de debugging temos que carregá-la na memória de um processo e colocar um breakpoint bem no entry point da DLL. Como fazer isso sabendo que um processo pode ter inúmeras DLLs em seu contexto?
É o que veremos agora através de um passo a passo.
Ambiente de testes
Iremos utilizar o Immunity Debugger para injetar uma DLL em um processo e colocaremos um Breakpoint no entry point da DLL injetada para realizar o debugging desde a primeira instrução como se fosse um executável normal.
Apenas para título de demonstração utilizarei arquivos comuns do Windows, o processo host será o IEXPLORE.EXE e a DLL será a p2p.dll, localizada em “C:\windows\system32\”. O software utilizado é o Immunity Debugger que pode ser baixado aqui, e também é necessária a instalação do Python 2.7 que pode ser obtido aqui.
Injeção de DLL em um processo
Segue o passo a passo do procedimento:
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á abrir 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.
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 e recuperar e exibir o número da Thread. Para isso digite os seguintes comandos na shell:
>>>thread = imm.injectDll("c:\\p2p.dll")
>>>
>>>print "Thread ID: 0x%X" % thread
Thread ID: 0x134
Injetamos a DLL e já recuperamos o número da nova Thread em um variável, depois exibimos esse número no formato hexadecimal.
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 precisemos executar o programa (F9) mais de uma vez.
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 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
>>>
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ó debugar a DLL normalmente.
Conclusão
Essa injeção de DLL com o uso do ImmDebugger não é muito conhecida, é difícil encontrar documentação a respeito e até em uma fonte mais confiável como um livro [1] não apresenta o procedimento de forma precisa, são necessários vários testes até atingir os resultados esperados.
Até a próxima!
[1] Malware Analyst's Cookbook and DVD (Publisher: Wiley; 1 edition (November 2, 2010)
Boa noite Ronaldo, muito bom esse poste, Ronaldo para vc que esta na area de analise de malwares, eu queria ter uma base por onde começar, oq devo me esforçar em aprender, se poder me ajudar fico muito grato :) abç
ResponderExcluirOlá Galdino, obrigado pelos comentários.
ResponderExcluirAntes de estudar assuntos específicos de malware é interessante conhecer bem o funcionamento interno dos computadores, tipo a arquitetura x86, SO, memória, etc. É bom entender bem de lógica de programação também e pelo menos uma linguagem como o C.
E sobre os malwares o melhor é estudar pelos livros de referência da área:
Pratical Malware Analysis
Malware Analyst's Cookbook and DVD
Malware Forensics
Hacking Exposed Malware and Rootkits
Sugiro também alguns materiais de introdução ao tema que tenho no blog:
http://www.crimesciberneticos.com/2011/12/introducao-engenharia-reversa-de.html
http://www.crimesciberneticos.com/2011/12/videos-da-palestra-no-hackn-rio.html
E por fim eu ministro um curso sobre o tema também, o banner está no blog à direita.
Abraços e bons estudos!
Opá muito obg, No final do ano será que tem uma turma pq eu só vou ter dinheiro livre no final do ano tipo novembro, se tiver me manda um email, que a gente conversa :)
ResponderExcluirabç Ronaldo, e sucesso...
Ótimo artigo! Me esclareceu muita coisa, fiquei espantado com espantado com esse debug de uma DLL.
ResponderExcluirTer um excelente material desse, raro e em portugues, é fantástico.
Sucesso. E como foi a prova da PF?
Olá Vagner, obrigado pelos comentários!
ExcluirNa verdade o concurso para perito da PF ainda não saiu, mas está pra sair.
Abraço!
Quando eu sei o comando imm.injectDll com outra DLL, apareceu o seguinte erro:
ResponderExcluirSintaxError: EOL while scanning string literal
Você sabe o que poderia ser?
Eu baixei o dll faltando e substituir http://pt.fix4dll.com/p2p_dll o arquivo antigo. Tudo correu bem e sem problemas. Eu não encontrar qualquer vírus.
ResponderExcluir