Pimptech Posted November 13, 2017 at 09:48 PM Share Posted November 13, 2017 at 09:48 PM Fala, galera! Espero que todos estejam bem. Vou trazer aqui para vocês hoje algo que eu desenvolvi para aprendizado, para melhorar minha análise de Windows Internals no geral. Acredito que pode ser válido para o aprendizado da galera aqui também. Eu não vou fazer algo detalhado, portanto para compreender totalmente esse post é requerido um mínimo de conhecimento em: Arquivos PE PEB - Portable Environment Block Linguagem C Assembly --EDIT-- Esqueci de postar o projeto Projeto Github https://github.com/bernardopadua/blog-inversing/tree/master/dll-manual-hijack Eu escrevi sobre os dois primeiros tópicos, mas ambos estão em inglês. Contudo o @Leandro Fróes fez uma série de tópicos sobre arquivos PE muito mais completo do que o que eu escrevi. E o @Fernando Mercês fez uma série de vídeos sobre a linguagem C. Bom, como eu disse antes eu fiz esse PoC para aprendizado se você também gosta de aprender irá aproveitar bem. Não é algo muito difícil de ser feito, porém as áreas que são necessárias para entender como se faz são importantes em engenharia reversa / análise de malware em geral. Do que se trata ? Eu tenho estudado mais afundo sobre PEB hooking ultimamente, que já é uma técnica antiga no ramo de DLL injection. PEB Hooking basicamente tem o objetivo de se infiltrar em um módulo já carregado por um processo. Depois de se infiltrar em um módulo o processo acessará as funções do módulo injetado FAKE e não o original. Porém para isso acontecer é necessário que a DLL injetada exporte as mesmas funções que a DLL original. Com isso eu desenvolvi uma tool que eu chamei de "DLL Exporter" (sou péssimo em nomear haha), essa tool acessa o Export Directory para exportar as funçoes que uma determinada DLL exporta. Com essas funções a ferramenta vai gerar dois arquivos para NASM, um com a extensão ".ext" e outro com a extensão ".subs". Cada um dos arquivos foram gerados por essa tool para ser embutidos no código principal. O exemplo que eu estou trazendo faz algo bem trivial e comum nos dias de hoje. O exemplo é um protótipo de troca de mensagem (mesmo não havendo nenhuma troca real) com "encoding" da mensagem para uma troca "segura" de tais mensagens. O exemplo em questão acessa uma função da DLL chamada 'send' para encodar e enviar a mensagem. Para fazer essa DLL hijacking/MITM a ideia é codar uma DLL que exporte a mesma função e que dentro dessa função ela chame a DLL original após nosso código customizado ser executado. Não há alteração no processo que faz a chamada da DLL e também não qualquer alteração na DLL original. A DLL fake irá fazer o load manual da DLL original e chamar a função original dentro da funão fake. Para fazer isso eu codei a DLL fake com o NASM e linkei a DLL com o GoLink. GoLink se encarregou de linkar o objeto gerado com as libs Kernel32, msvcrt e a dllsend. O nome de DLL que eu utilizei no exemplo foi "dllsend.dll". Problemas ? Como tive que renomear a DLL fake com o mesmo nome da DLL original, quando o Windows Loader vai tentar fazer o load da DLL original (mesmo nome da DLL fake) ele já acha a DLL carregada no espaço de endereços de memória do processo (a fake DLL), com isso a IAT (Import Address Table) é carregada com os endereços da própria DLL fake. No fim isso acaba gerando um Deadlock, a fake DLL quando chamada pelo processo e tenta executar a função da DLL original acaba chamando a si mesma infinitamente. Solução! Para resolver esse problema eu tive que fazer o Load da DLL original com a API LoadLibraryA, acessar o "module" da DLL fake para guardar o endereço de IAT da DLL. Acessar o "module" da DLL original para acessar e guardar o endereço do campo AddressOfFunctions localizado dentro da Export Directory. A inteção aqui é iterar sobre a AddressOfFunctions e sobrescrever a IAT com os endereços da função original. Contudo as páginas de memória onde a IAT está localizada está protegida contra gravação e para resolver isso precisei utilizar outra API VirtualProtectEx para alterar a proteção do espaço de memória onde a IAT está localizada. Divisão do projeto Cada pasta do projeto possui um make.ps1 para compilar o objeto de cada pasta. dll Esta pasta contém o código da dllsend.dll dll-consume Esta pasta contém o código do programa que consome a dllsend.dll. dll-exporter Esta pasta contém a tool "DLL Exporter" que exporta as funções de uma determinada dll. A ferramenta gera dois arquivos {NOME_DLL}.DLL.EXT E {NOME_DLL}.DLL.SUBS. .EXT: Este arquivo contém o código NASM para indicar uma função importada com a diretiva "extern". .SUBS: Este arquivo contem a declaração NASM da função exportada. dll-fake-asm Esta pasta contém a DLL fake codificada. É totalmente codada em NASM com uma section especial chamada drectve. Essa section especial é lida pelo GoLink para importar as libs informadas lá. make.ps1: Tem toda a lógica para compilar e linkar a DLL. Análise do processo A ordem de compilação é indiferente, porém pode fazer dll-consume, dll e dll-fake-asm. Vou assumir que você tenha compilado tudo certo. The program dll-consume é bastante simples e bem intuitivo. Você digita a mensagem e o programa faz o "encoding" da mensagem e faz o envio (não de verdade). Para fazer processo funcionar eu renomeei a DLL original com o final "2". Como a DLL fake foi codada em NASM o tamanho é muito diferente, pois não tem todos os apetrechos da GCC. Vamos ver como fica a lista de arquivos na pasta. Talvez alguns de vocês ainda não estjam cientes, porém o entry point dos programas compilados com o GCC não são diretamente da main. O entry point criado pelo GCC é um "pré-código" de inicialização de todo o ambiente para então executar o OEP (original entry point). Você pode debugar linha a linha e achar o entry point ou pode ir direto ao assunto e procurar pelas "inter-modular calls" feitas pelo módulo m.exe para o módulo dllsend.dll. Esta é a main function do programa: Se você não esta muito acostumado com assembly, minha dica seria treinar. Resolva crackmes, codifique em C e debug seu próprio programa, mas não em IDE, ao invés disso direto no assembly. É necessário treinar os olhos para ler assembly e idenficar padrões de chamada/instruções. Eu coloquei o mouse na linha que faz a chamada para a função send e o x64dbg gerou um preview do destino da chamada. Esse jmp faz um salto para o endereço da função send gravado na IAT do módulo m.exe. Nesse ponto de execução a DLL fake já foi inicializada e já inicializou a DLL original também. Essas informações podem ser chacadas na aba de Memory Map. Se você quiser debugar todo o processo de inicialização (recomendo MUITO) da DLL original e do processo de reescrita da IAT você vai precisar debugar a entry function da dllsend.dll (fake dll). Para fazer isso é necessário habilitar no x64dbg a opção DLL Entry. Ele vai pausar a execução no início de cada DLL, só ir dando F9 até chegar na dllsend.dll. Eu achei função send da dllsend.dll e coloquei um break point lá para debugar. Dentro da execução podemos ver o código que loga todas as menssagens enviadas pelo programa. Como você pode ver no código assembly gerado, estou utilizando fopen, fwrite e fclose. Com esse padrão de chamada fica visível que eu estou logando as informações em algum arquivo antes de efetuar o JMP (salto) para a função send original. Usei pushad e popad para salvar o contexto de registradores antes de executar minha função custom. E não podemos esquecer que a lib msvcrt é __cdecl(calling convention) o chamador (caller) que limpa a stack. Eu recomendo a debugar o processo de escrita da IAT para aprender (se quiser). Abre a DLL no CFF Explorer e vai debugando ao mesmo tempo. Como evitar isso ? Até existem algumas medidas para tentar bloquear esse tipo de coisa. Podemos checar a MD5 da DLL antes de efetuarmos a chamada para ela, se for diferente da MD5 armazenada, então seu programa foi comprometido. Podemos também checar na PEB (LdrModules) quantos módulos existem dentro do espaço de endereços do processo, se tiver qualquer módulo a mais podemos concluir que houve uma dll injection ou algo parecido, como esse hijacking/MITM. Mas a gente sabe que é mais complicado do que isso. O que o programadores realmente podem fazer é deixar a engenharia reversa muito mais difícil de ser realizada. E para isso o programador tem que saber usar as técnicas de engenharia reversa. Bom galera, sei que não é muita coisa, mas acho que talvez ajude alguém. Qualquer dúvida, crítica, sugestão ou correção fique à vontade para comentar. Estamos ai para aprender. Abraço! Post Original https://verseinversing.blogspot.com/2017/11/manually-hijacking-dll-mitm-dll.html Link to comment Share on other sites More sharing options...
Moderators Leandro Fróes Posted November 19, 2017 at 02:05 AM Moderators Share Posted November 19, 2017 at 02:05 AM Legal pra caramba esse post mano, cai justamente no que estou estudando. Obrigado pela referência, não tenho tido tanto tempo pra finalizar o tutorial, mas assim que o fizer será justamente sobre directories e sections, será um prazer ter sua leitura. Abraços!! Link to comment Share on other sites More sharing options...
Pimptech Posted November 19, 2017 at 08:27 PM Author Share Posted November 19, 2017 at 08:27 PM 18 horas atrás, Leandro Fróes disse: Legal pra caramba esse post mano, cai justamente no que estou estudando. Obrigado pela referência, não tenho tido tanto tempo pra finalizar o tutorial, mas assim que o fizer será justamente sobre directories e sections, será um prazer ter sua leitura. Abraços!! Bacana, mano! Essas partes são bem interessantes de forma geral. Com certeza irei ler quando postar. Fico aguardando! Abraço! Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.