Jump to content
  • Hookando funções no Windows com o API Inspector

       (1 review)

    Vou começar agradecendo ao @Fernando Mercês pela oportunidade e por ter sugerido este artigo, que também me motivou bastante a escrevê-lo!

    Introdução

    Não sou conhecido internet a dentro, apenas acompanho alguns canais no Discord (tal como o do Mente Binária). Meu nível de programação e engenharia reversa não é algo admirável ainda. Em um grupo especifico intitulado "Terra do 1337", que é um grupo fechado de amigos com finalidade de estudar engenharia reversa, programação e descontrair, eu surgi com uma idéia de escrever uma ferramenta que iria facilitar a vida de muitos nesta área de engenharia reversa e achei de API Inspector.

    A seguir um spoiler de como foi o início do projeto, para quem se interessar. ?

    Spoiler

    O início do projeto consistia em um console que se comunicava com uma DLL anexada ao processo (obrigado imensamente ao iPower por sugerir esse tipo de conexão, no caso por pipe. Mesmo o projeto depois deixando isto de lado e tomando outro rumo, essa conexão também encontra-se em meu Github), com isso eu poderia obter as informações internamente com a DLL e as enviar ao interpretador que era um executável.

    A primeira versão chamava-se HookInspector. Ignore o erro de formatação do data type LPWSTR na imagem a seguir. ?

    2011613001_unknown(1).png.21dadd6289bbb93bd4bc58753b2186e9.png

    Na imagem à direita, temos a DLL fazendo seu papel internamente no Notepad++ e do lado esquerdo o executável que recebia as informações da DLL.

    unknown.png.fb669f550c4c552b6f4ab953f231a97d.png

    O projeto também acabou mudando de nome. De HookInspector, passou a se chamar NTDLLInspector, já que iria visar somente funções da API ntdll.dll (x86).

    Porém eu vi a necessidade de fazer uma GUI porque em console (CLI) além de não ser tão bom visualmente dava muito trabalho (não que agora eu não tenha, mas é bem menor). Foi aí que o ImGui entrou em ação e passei a tratar o projeto como API Inspector, utilizando DirectX11.

    Enfrentei dois problemas nessa situação: o primeiro já foi corrigido (consumo extremo de CPU usando DirectX11, de 30% a 50%). A correção veio junto com um downgrade para DirectX9, o que também garantiu maior compatibilidade.

    O segundo problema ainda existe e já existia na primeira versão (de console), que é a dificuldade em obter as informações dos argumentos e encaminhá-las formatadas para o logger e para o ImGui renderizar. Justamente por ter essas dificuldades que eu pensei em abrir o código do projeto, para que este cresça. ?

    O que é o API Inspector

    É uma ferramenta de código-aberto voltada para área de engenharia reversa, que irá auxiliar na análise de funções correspondentes a certas API's do Windows, retornando informações obtidas dos argumentos caso a função seja chamada pela aplicação.

    O que ele faz

    Ele faz um hook (do Inglês "gancho"), que consiste num desvio na função original da API solicitada para nossa própria função e com isso podemos obter os dados (argumentos/parâmetros) que foram passados para tal função.

    Como ele funciona

    O princípio de um hook é simples: você insere no inicio da função um salto que irá levar para a sua função (que é uma cópia da função original) e depois de efetuar o que quiser, irá retornar para a função original prosseguir.

    Talvez mais fácil visualizar o que expliquei com código:

    //Aqui está a função //ZwWriteVirtualMemory | NtWriteVirtualMemory, originada do binário: ntdll.dll
    //créditos ao https://undocumented.ntinternals.net/
    NTSYSAPI 
    NTSTATUS
    NTAPI //WINAPI
    
    NtWriteVirtualMemory(
      IN HANDLE               ProcessHandle,
      IN PVOID                BaseAddress,
      IN PVOID                Buffer,
      IN ULONG                NumberOfBytesToWrite,
      OUT PULONG              NumberOfBytesWritten OPTIONAL );
    
    //Sua versão assembly
    
    777F2110          mov eax,0x3A
    777F2115          mov edx,ntdll.77808D30
    777F211A          call edx
    777F211C          ret 0x14
    
    //O que nós vamos fazer é criar uma função similar á ela com o nome que decidirmos
    //Então vamos inserir um jmp no início da função original para nossa função, ficando assim:
      
    777F2110          jmp api inspector.573523EC
    777F2115          mov edx,ntdll.77808D30
    777F211A          call edx
    777F211C          ret 0x14
    
    //Usei como exemplo minha próprio ferramenta!
    //Então quando ocorrer a chamada desta função ela será jogada em nossa função! Depois de nós fazermos que desejar vamos retorna-la, porém para uma região que aloquei onde contém
    //Um buffer dos bytes que foram sobrescritos da função original:
      
    03610000          mov eax,0x3A
    03610005          jmp ntdll.777F2115
    
    //Ela irá retornar depois do jmp que existe na função original e continuar o código....

    Vantagens de se utilizar o API Inspector ao invés de um debugger

    Imagine que você está visualizando as chamadas intermodulares (para bibliotecas externas, no caso) que um programa faz, utilizando um debugger (o x64dbg por exemplo) e notou que uma certa função que deseja inspecionar é chamada em diversos pontos do programa. Vejo duas opções neste caso: colocar vários breakpoints, um em cada chamada à função, no código do programa ou colocar um único breakpoint função em si, no código dela, na DLL.

    Em ambos os casos, você vai precisar analisar chamada por chamada, parâmetro por parâmetro. E se a função for chamada 20 vezes consecutivamente? O tempo que você levaria para visualizar apenas o primeiro parâmetro da chamada é o tempo que a ferramenta iria levar para exibir todas as 20 chamadas, com os argumentos formatados bonitinhos ao seu dispor. Entende a vantagem? ?

    E as desvantagens?

    Por hora, uma desvantagem é a quantidade de funções e API's suportadas. De fato, a primeira release não possui uma quantidade significativa que vá fazer você utilizar a ferramenta e nem uma quantidade de recursos interessantes na ferramenta. Mas é ai que vem o ponto chave, o fato de deixar ela pública remete ao próprio crescimento da mesma, no primeiro momento é necessário uma orientação da parte de vocês para me ajudar a melhorar o código visual. O segundo passo é eu e vocês começarem a fornecerem mais recursos para ela. Eu irei adicionar todo ou qualquer recurso que seja significativo para a mesma, e para isso eu já tenho mais funcionalidades para implementar na ferramenta que são excelentes.

    Interface gráfica

    Na imagem abaixo, utilizei o API Inspector para hookar a função MessageBoxW() da USER32.DLL. Depois disso, escrevi um texto num novo arquivo no Notepad++ e tentei fechar o programa. Ao fazer isso, o Notepad++ perguntou se eu queria salvar o arquivo e ele faz isso através de uma chamada à MessageBoxW(), que o API Inspector interceptou prontamente.

    Screenshot_1.thumb.png.8501231abce62d2f799122ed5a687f18.png

    Na imagem acima, a janela à esquerda mostra o que está atualmente passando pelas funções hookadas. Na janela a direita, temos um log.

    Como utilizar o API Inspector

    A única coisa que você precisa fazer é anexar a DLL do API Inspector ao processo desejado e para isso existem os softwares chamados "Injetores de DLL" que podem ser achados na internet.

    Você também pode criar o seu próprio injetor. Uma dica é pesquisar sobre injeção com a função LoadLibrary(), mas no exemplo a seguir eu vou mostrar como utilizar o Process Hacker para fazer a injeção.

    1 - Abra o Process Hacker e identifique no mesmo o processo no qual você quer injectar a DLL do API Inspector. No exemplo, usei o processo do Notepad++.

    Screenshot_2.png.a6db50cce5317153c5ed675a9ca98e95.png

    2 - Clique com o botão direito sobre o processo e escolha Miscellaneous > Inject DLL.

    Screenshot_3.png.be7aec2984c520ddfbe088ac69e8bd9f.png

    3 - Selecione a DLL API-Inspector.dll e clique em Abrir.

    Screenshot_4.png.deae66a97a357d33d213933a7654cb9e.png

    4 - Se o Process Hacker possuir privilégios suficientes a ferramenta irá ser carregada, caso contrário, não.

    Screenshot_5.thumb.png.574f17bc0fc93998d7ae358ccc494874.png

    Após isso você precisa selecionar a API desejada, a função desejada e clicar em GO Hook!

    O step call é uma funcionalidade que vai fazer a ferramenta aguardar o pressionamento da tecla ENTER para retornar para a função original. Pronto, o seu hook está feito e você já poderá inspecionar a função desejada.

    Download e código

    No repositório do API Inspector no Github você pode baixar a versão compilada e ter acesso ao código-fonte também. Contribuições são muito bem vindas!

    Bom, eu nunca tinha escrito um artigo. Se faltou informação ou coloquei informação demais me desculpe. Estou aberto pra ler os comentários. Ah, e participem deste projeto! Eu quero fazer ele crescer muito. Caso precise de referências de como cheguei a este projeto, tem tudo na página inicial do projeto no Github.

    Agradecimentos

    Obrigado novamente ao Fernando Mercês, ao pessoal do Terra 1337 que me incentiva cada vez mais e em especial para o iPower e Luan que são colaboradores do projeto.

    Referências

    • Curtir 5
    • Haha 1

    User Feedback

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest


  • Similar Content

    • By Leandro Fróes
      Se você é da área de Segurança da Informação ou simplesmente tem interesse pelo assunto já deve ter notado que todo dia temos notícias de novos malwares surgindo, sejam eles malwares completamente novos ou variantes de um malware já conhecido. Com isto em mente, faz algum tempo que as empresas de segurança, inteligência e até mesmo pesquisadores independentes passaram a buscar métodos de automatizar não só a análise destes malwares, mas também a administração e armazenamento do arquivo em si, suas características e relacionamentos com outros arquivos demais entidades (domínios, campanhas, endereços IP, etc). Obviamente a análise automatizada não substitui a análise humana, mas já é uma ajuda e tanto considerando o número de malwares surgindo diariamente.
      Para cada uma destas necessidades descritas anteriormente existe uma ou mais ferramentas/plataformas que podem ser utilizadas para cumprir estes objetivos. Dentre elas estão plataformas de sandboxing  como Hybrid-Analysis e AnyRun, ferramentas de análise estática de arquivos como o DIE (Detect It Easy), pev, yara, capa, e também repositórios de malware como o VirusShare e o Malware Bazaar.
      Não podemos negar que todas estas ferramentas/plataformas ajudam e muito no nosso dia a dia, mas ainda assim não conseguiríamos organizar nossas informações e centralizá-las em um único lugar de forma automática, tendo em vista que as as soluções descritas acima são isoladas e não conectam umas com as outras de forma nativa. A plataforma que chegou mais próximo de atingir as quatro exigências (isto é: análise automatizada, administração, armazenamento, relacionamento com demais entidades) foi uma plataforma chamada Virus Total, também conhecido como VT, atualmente administrado pelo Google.
      Virus Total
      O Virus Total trouxe para a comunidade uma forma simples e rápida de análise de IoCs (Indicator of Compromise) e também uma API bem simples de se utilizar para fins de automação. Dentre as diversas funcionalidades da plataforma estão inclusas análise estática, checagem de assinatura utilizando uma lista gigantesca de Anti-Virus, descrição das características gerais do IoC e comentários da comunidade. Além disso, ele também possui uma versão paga (bem cara por sinal) onde você pode fazer hunting de malwares utilizando regras de Yara, download de arquivos, buscas baseadas em histórico, visualização gráfica e uma API bem mais robusta e permissiva.
      É importante deixar claro que o termo IoC não se refere apenas à arquivos e seus hash, mas também à URL, domínios e IP. Ou seja, o VT realmente acaba se tornando uma opção super viável para começar qualquer tipo de investigação.
      O cenário atual de Segurança da Informação
      Com o passar do tempo não só a comunidade, mas também o mercado de Segurança da Informação no geral passou a notar que a única forma de se posicionar contra os ataques atuais é através de contribuição. Pelo mesmo motivo que gerou a necessidade de se criar formas automatizadas de análise, a contribuição se mostra cada dia mais que necessária pois ela não impõe limites, muito pelo contrário, ela dá liberdade o suficiente para você contribuir da forma que quiser.
      Um ótimo exemplo que mostra o exercício da contribuição e o quão valioso isto pode ser é o próprio Linux, que desde sua primeira versão foi liberado para receber contribuições e hoje é um dos maiores projetos existentes na área de tecnologia, com milhares de contribuidores ao redor do mundo.
      Com isto em mente, podemos notar uma desvantagem no VT: o espaço para contribuição é limitado.
      Desafios
      Como já comentado anteriormente, as principais funcionalidades são suportadas apenas na versão paga e infelizmente não são todos que podem pagar pelo valor do serviço.
      Um dos principais motivos dessa limitação é fato do código não ser aberto, isto é, estamos presos às funcionalidades que o time do VT disponibiliza. Se o código fosse disponível para a comunidade, resolveríamos tanto o problema monetário quanto a limitação de funcionalidades disponíveis.
      Uma outra porta que seria aberta no cenário descrito acima é a seguinte: Imagine que você, sua empresa, seu time ou um grupo de amigos estão com um projeto em mãos que envolve análise, classificação, categorização ou qualquer tipo de manipulação de malware. Com o código em mãos você teria liberdade de fazer a instalação da plataforma localmente ou em um servidor do qual você controla, limitando o acesso à quem você quiser e como quiser.
      A comunidade
      Tendo estes desafios em mente, a comunidade começou a criar alternativas para resolver alguns problemas encontrados no cenário atual. A ideia do artigo não é de forma alguma dizer que uma plataforma é melhor que outra ou que o Virus Total está errado em trabalhar no modelo que trabalha, muito pelo contrário, o objetivo aqui é mostrar as várias formas que temos de se chegar no mesmo objetivo. Uns mais flexíveis, outros com mais conteúdo disponível, mas todos conseguem te ajudar a chegar no mesmo lugar:
      Saferwall: Este é o projeto mais maduro que temos atualmente quando o assunto é análise automatizada e contribuição da comunidade. Robusto e flexível para ser instalado em  diversos ambientes, o Saferwall consegue entregar informações estáticas de arquivos, detecções baseadas em assinaturas de alguns antivírus, identificações de packers e download dos arquivos submetidos anteriormente. Além disso, o Saferwall possui uma plataforma aberta e que aceita colaboração, além de disponibilizar o código para você instalar onde e como bem entender. Dentre as formas de instalação estão inclusas o minikube (indicado para ambientes de testes), em nuvem utilizando AWS e On-Premise.


      Freki: O projeto Freki foi criado por uma única pessoa, mas não deixa a desejar quando o assunto é funcionalidade e fácil instalação. Com possibilidade de ser instalado utilizando Docker, este projeto possui não só análise estática dos arquivos PE submetidos, mas também disponibiliza sua própria API e puxa informações do VT para garantir que não falte nada.


      Aleph: focando bastante na parte de inteligência, o projeto Aleph entrega para você não só informações estáticas dos arquivos submetidos, mas também análise dinâmica utilizando sandbox, visualização gráfica dos resultados e uma saída em JSON formatada para ser utilizada em backends como Elasticsearch, por exemplo. Além disso, o Aleph também consegue mapear as técnicas utilizadas pelo malware utilizando o MITRE ATT&CK Framework. Eu realmente aconselho você dar uma olhada na palestra da MBConf v3 sobre o Aleph para saber mais sobre o projeto.
       


      A tabela à seguir foi criada para facilitar a visualização das funcionalidades descritas acima. É importante deixar claro que a versão do VT utilizada para a criação da tabela é a gratuita:
       
       
      VirusTotal
      Saferwall
      Freki
      Aleph
      Análise Estática
      ✔️
      ✔️
      ✔️
      ✔️
      Análise Dinâmica
       
      X
       
      ✔️
       
      X
       
      ✔️
       
      Suporte à múltiplos SO
      ✔️
       
      ✔️
       
      X
       
      ✔️
       
      Análise de IoC de rede
      ✔️
       
      X
       
      X
       
      X
       
      Código Aberto
      X
       
      ✔️
       
      ✔️
       
      ✔️
       
      Download de arquivos
       
      X
       
      ✔️
       
      ✔️
       
      ✔️
       
      Instalação local
      X
       
      ✔️
       
      ✔️
       
      ✔️
       
      Controle total do backend
      X
       
      ✔️
       
      ✔️
       
      ✔️
       
      API
       
      ✔️
       
      ✔️
       
      ✔️
       
      X
      Como podemos ver, todos estes projetos são de código aberto, o que permite a seus usuários livre contribuição. Caso você tenha interesse em contribuir para alguns desses projetos, aqui vai uma dica: nenhum deles possui ainda análise de URL/IP/domínio de forma isolada, isto é, independente do arquivo. Tenho certeza que uma contribuição deste tipo seria bem vinda. ?
      Conclusão
      Ajudando estes projetos nós não só melhoramos a ferramenta/plataforma em si, mas ajudamos todos que a utilizam e também construímos um sistema livre e aberto de análise, inteligência e investigação.
      Se você é da área ou simplesmente curte contribuir, não deixe de dar uma olhada em cada um destes projetos e, se possível, contribuir com eles. Lembrando que quando falamos de contribuição, não há limites. Pode ser um commit, uma ideia, ajuda monetária ou um simples OBRIGADO aos desenvolvedores e contribuidores por disponibilizarem projetos tão úteis para a comunidade.
    • By Fernando Mercês
      Passei um tempo usando o Windows 10 depois de anos em Linux e macOS. Logo percebi dificuldades específicas com shell, instalação de programas, etc. Mas também percebi que é possível deixar o Windows muito próximo, no quesito de usabilidade, de um Linux com shell completo ou macOS. Neste artigo vou mostrar as ferramentas e configurações que mais me ajudaram. Boa leitura! 😉
       
      Gerenciador de pacotes
      Vou começar falando dele por um motivo muito simples: outros programas podem ser instalados com ele. Pois é, parece que a Microsoft aprendeu com as distros Linux e projetos como o Chocolatey, já que finalmente anunciou seu gerenciador de pacotes, o winget. Para instalar, baixe o arquivo com extensão .appxbundle na área de releases do repositório do projeto no Github. Após isso você pode abrir qualquer terminal (Command Prompt / cmd.exe ou Powershell) e digitar winget pra ver seu novo gerenciador de pacotes:

      Vamos buscar por exemplo os programas que que tenham a palavra "security" em seu nome ou descrição, para testar:

      Qualquer um desses programas pode ser instalado com um simples "winget install". Faça o teste com o Notepad++ por exemplo:
      winget install notepad++ Os comandos list (listar os programas instalados) e upgrade (atualizar os programas instalados) ainda são experimentais, mas você pode habilitá-los da seguinte maneira:
      Digite winget settings no terminal. Um arquivo settings.json se abrirá. Nele, adicione: "experimentalFeatures": { "list" : true, "upgrade" : true }, O meu aqui tá assim:

      A lista de programas disponíveis está aumentando cada vez mais, já que o winget é de código aberto. 🙂
       
      Terminal decente
      Mas na real, a primeira coisa de que senti falta foi um terminal decente. Graças a Deus encontrei o Windows Terminal. Para instalar com o winget (não se assuste - dá pra usar a tecla Tab para autocompletar):
      winget install Microsoft.WindowsTerminalPreview Aí olha só quem chega na festa:

      Este terminal concentra tudo em um: Prompt de Comando, Powershell e Linux (rodando via WSL), e é multi-abas. Claro que tá longe de um Terminator ou iTerm2, mas também tá longe de um cmd.exe né? Deus me livre e guarde! kkkk
      O novo Windows Terminal também tem uma configuração baseada em JSON e uns recursos interessantes como a divisão automática da janela do terminal. Ao apertar Alt+Shitft+D, olha o que acontece:

      terminal_split.mp4 A divisão da janela (split) funciona para janelas com qualquer shell.
       
      Hashes
      Eu sempre curti um software pra Windows chamado TotalHash, que adiciona os hashes de arquivos em suas propriedades, mas este infelizmente tem dois problemas: não é livre nem suporta plugins (logo, não consigo extender para suportar os hashes que preciso), é pago e não é scriptável. Resolvi isso com o cmdlet Get-FieHash do Powershell. Por padrão ele exibe o SHA-256 de um arquivo, mas há várias opções, como se pode observar na imagem:

       
      Sniffer
      Por essa nem o futuro esperava! O Windows 10 agora tem um sniffer nativo: o pktmon. Se liga:

      E sim, ele suporta filtros. Por exemplo, para logar somente pacotes IPv4 na porta 80/tcp:
      pktmon filter add HttpPuro -d ipv4 -t tcp -p 80 Você pode adicionar mais de um filtro se quiser e com qualquer nome (aqui chamei o meu de HttpPuro). Depois, é só iniciar a captura pedindo para logar os eventos:
      pktmon start --etw Para parar a captura, o comando é o stop:
      pktmon stop Por padrão o pktmon cria um arquivo chamado PktMon.etl num formato próprio. Este pode ser convertido para texto:
      pktmon format PktMon.etl -o log.txt Ou para o formato PCAP-NG, suportado pelo Wireshark e outros analisadores de pacotes:
      pktmon pcapng PktMon.etl -o capture.pcap Há várias outras opções que valem serem exploradas. É de fato um sniffer completo.
      Em breve vou falar mais sobre as seguintes ferramentas:
      PowerToys Sysinternals O novo diskusage.exe. WSL 2.0. Por hora é isso. Conforme eu encontre coisas novas, vou adicionando aqui. Se souber de alguma novidade ou algo que ache que precise ser citado aqui, por favor comente aí embaixo!
      Espero que seja útil para quem precisa usar o Windows por algum tempo, por qualquer motivo. 🙂
    • By Leandro Fróes
      Faz algum tempo que ando botando mais a mão na massa na parte prática da análise de malware e nos conceitos que a envolvem. Este fato somado com minha paixão por tomar notas nos meus estudos acaba resultando na criação de alguns relatórios. Com isto em mente, decidi colocar aqui a análise do último sample no qual trabalhei, de um ransomware chamado Nephilin.   Overview   O Nephilin é uma variante do Nefilim, um Ransomware que acabou ficando bem conhecido no mês de fevereiro/março devido ao fato de ser uma variante do conhecido Nemty, que costumava trabalhar com operações de RaaS (Ransomware as a Service - um modelo de negócio utilizado por criminosos que facilita muito a distribuição de Ransomwares. Basicamente o criador do malware recruta pessoas para usarem o Ransomware e recebe uma parte de seus lucros, facilitando assim a distribuição e a entrada de pessoas não experientes no crime). Por mais que as formas de operação sejam diferentes, há similaridades de código entre essas três famílias de malware.   Análise Estática   O sample analisado foi compilado para x86 e não possui nenhuma técnica que possa dificultar nossa análise como por exemplo packers/protectors e o uso de ASLR. No entanto, este binário é assinado com um certificado válido:     Olhando os imports podemos notar que a Import Directory Table possui apenas uma entrada, a da kernel32.dll, levantando a suspeita da utilização de runtime linking, ou seja, o loader não resolve o endereço das funções em tempo de carregamento, pois eles são resolvidos em tempo de execução:     Podemos suspeitar ainda mais pelo fato do nome algumas DLLs estarem na lista de strings do binário, assim como o nome de algumas funções que não são exportadas pela kernel32.dll:     Não vou me preocupar muito com esta parte estática da análise, tendo em vista que a ideia deste artigo é cair de cabeça em cada funcionalidade do malware, isto é, executá-lo e ir analisando seu comportamento.   Análise Dinâmica   A primeira função que o malware chama é a que vai criar todo o contexto de criptografia para gerar uma chave que será a chave utilizada para descriptografar a Ransom Note:       Dentro desta função existem várias funções que permitem trabalhar com criptografia no Windows. A primeira função criptográfica chamada é a CryptAcquireContext, responsável por criar um handle para um key container dentro de um Cryptographic Service Provider (CSP). Após pegar o handle, o tamanho de uma string é calculado para posteriormente se criar e retornar um Hash Object dentro do CSP criado anteriormente. Esta string tem 66 bytes de tamanho (0x42 em hexa) e é uma string lotada de "a".    A função CryptCreateHash cria o Hash Object especificando o tipo como SHA1 e, logo depois, a função CryptHashData tira o hash do que está dentro de um buffer de tamanho 66 bytes sendo passado como parâmetro:         Por fim, o SHA1 gerado é derivado, para a geração de uma chave RC4. Como podemos ver quase todas as funções estão sendo importadas dinamicamente. ?   O que acontece após a função que gera esta chave RC4 é a criação de um Mutex com o nome "sofos delaet sosos":     Em seguida, uma string em base64 aparece e é decodada com a função CryptStringToBinary, resultando em uma chave pública RSA:   "BgIAAACkAABSU0ExAAgAAAEAAQDNFw18bUF1x32DZaZt4gnQtAnv5XH60d9B6UgIbVfRdHPeyEljZLKlGBKFPTsh+8xsDHe/9vynuOlnuPt91grReMAwcTDVkxBh/PDkf3Jq0bnFgZAWbgMvGX6lApXTDcTArf4US63VI3z8YPyDNJwEvBEWI13ywob8ECLsrD/C6BPkYG0mBU1ccixzOgkgad0iDvwS/C8iyW1Mi0PCoBa+3TCTVwt0Zpy/HceV5U7SevG7RRN5HrErv54Ihg6kTPPhdxkYdO+CUND19aLqh8MAVLRuP5hR6b6r7cjBNAW2+USaaMyT/llNXdPdySbatLlH6Mau4z1eqzYc7hMB2f+6"       Há depois uma tentativa de pegar um handle para um CSP onde o key container tem o nome  "rsa session" e, sem sucesso, o binário cria um novo chamado "skr skr skr":     Agora a chave pública decodada anteriormente será importada para o contexto "skr skr skr":       Ações padrão da maioria dos ransomwares incluem desabilitar a checagem de erros durante o boot, desabilitar o modo de recuperação, deletar backups, etc. O Nephlin faz isso através de uma chamada à função ShellExecuteA() passando uma linha com o cmd.exe como parâmetro:   "C:\\asdfgsdgasd\\..\\Windows\\asdgagsahsfahfhasahfsd\\..\\System32\\cmd.exe" "/c bcdedit /set {default} bootstatuspolicy ignoreallfailures & bcdedit /set {default} recoveryenabled no & wbadmin delete catalog -quiet & wmic shadowcopy delete"     Aqui foi utilizada uma abordagem um tanto curiosa, tendo em vista que o malware considera diretórios que provavelmente não existirão no sistema de arquivos da vítima ("asdgagsahsfahfhasahfsd", por exemplo) e sobe um nível no filesystem utilizando ".." para acessar de fato o que importa, ou seja, o caminho real seria simplesmente "C:\Windows\System32\cmd.exe" ?   Neste momento acontece uma checagem em relação à como o malware foi executado na linha de comando. Se foi passado algum parâmetro, ele checa pra ver se é um arquivo ou diretório. Se for um arquivo, ele chama direto a função que encripta. Caso seja um diretório, ele chama a função que checa uma lista de exclusão dos tipos de arquivos que ele não quer encriptar e esta função chama então a função que encripta.   É interessante notar que com essas checagens o ransomware pode ser usado em diversos cenários e não simplesmente para encriptar o sistema completamente. Ex: para manualmente testar se ele está funcionando (antes da possível invasão), ser executado manualmente após a invasão visando diretórios/arquivos específicos, etc:     Se nenhum parâmetro for passado via linha de comando, o binário começa a mapear os drives que estão no sistema e pegar seus tipos, buscando especificamente por drives fixos, removíveis (pen drives, etc) e mapeamentos de rede:     Após pegar o drive o seu nome é concatenado com a string "NEPHILIN-DECRYPT.txt", à fim de criar a Ransom Note na raiz do Drive em questão:     Após a chamada à CreateFile, podemos ver a Ransom Note sendo criada, mas vazia por enquanto:     Antes do conteúdo ser de fato escrito no arquivo, ele precisa ser decodado, tendo em vista que é uma string em base64 (sim, outra string em base64):     Abaixo está o buffer que contém o conteúdo da Ransom Note em base64:     Após decodar o base64 o buffer aparenta estar encriptado, e de fato está:     A função CryptDecrypt utiliza a chave RC4 gerada anteriormente para decriptar o conteúdo do buffer em questão. Podemos ver o conteúdo em clear text após a execução da função:     Por fim podemos ver a função WriteFile, que irá escrever o conteúdo no arquivo "NEPHILIN-DECRYPT.txt" criado anteriormente:       Agora que a Ransom Note foi criada, o processo de criptografia começa. O meio utilizado é através da criação de outra thread, isto é, para cada drive encontrado, uma nova thread é criada. A função CreateThread recebe como parâmetro para indicar seu início o endereço de uma função, que por sua vez chama a função que checa a lista de exclusão e depois começa a criptografia. Além disso, o nome do drive escolhido no momento é passado como parâmetro para esta função.

      Esta lista de exclusão é basicamente um lista que contém nomes de arquivos, diretórios e extensões das quais o malware não irá encriptar. Para cada arquivo encontrado o malware irá comparar com as especificações desta lista e, caso não bata, a função de criptografia será chamada:           Criptografia   A criptografia pode começar de 3 formas diferentes, como mencionado anteriormente: passando um arquivo como parâmetro pela linha de comando, passando um diretório ou mapeando os drives e criando threads.   Um trecho da função que faz as devidas checagens pode ser observada abaixo:     Se o arquivo checado não estiver na lista de exclusão, a função de criptografia é chamada:     O processo de criptografia se inicia com a abertura do arquivo em questão e a obtenção do seu tamanho. Depois disso, há duas chamadas para a função SystemFunction036 para gerar números aleatórios. Basicamente esta função é um alias para a função RtlGenRandom, que recebe como parâmetro um buffer e o tamanho do número aleatório que você quer gerar. O tamanho escolhido são 16 bytes (0x10):       Tendo 2 buffers de 10 bytes de tamanho cada, com os devidos números aleatórios gerados anteriormente, há duas chamadas à CryptEncrypt, uma para cada buffer. Aqui a chave pública RSA é utilizada para encriptar o buffer em questão, resultando em outros dois buffers de 256 bytes cada.       O conjunto de funções a seguir faz a mesma operação, mas apontando para lugares diferentes. A função SetFilePointerEx é utilizada para apontar para o fim do arquivo (baseando-se no tamanho obtido anteriormente) e depois a função WriteFile é utilizada para escrever os 256 bytes encriptados lá. A próxima chamada à SetFilePointerEx agora aponta para o fim do arquivo + 256 bytes e então escreve o segundo buffer encriptado onde o ponteiro está apontando.       Neste momento as checagens de tamanho de arquivo começam, assim como as chamadas de função e loops que envolvem a criptografia.   A primeira checagem feita é se o arquivo é maior que 64MB e, caso seja, as funções que criptografam o arquivo começam a ser chamadas de 125KB em 125KB. Caso o arquivo seja menor há uma outra checagem para ver se ele é menor que 1.2MB e caso ele não seja as funções de criptografia rodam em cima de 600KB apenas e finalizam. Caso o arquivo seja menor que 1.2MB ele é encriptado "de uma vez" e depois finaliza.         Para cada arquivo é gerada uma chave randômica com a função SystemFunction036 e depois esta é encriptada com a chave RSA pública. Esta abordagem dificulta bastante a criação de um decryptor, tendo em vista que a chave será sempre aleatória. Por outro lado, se tivemos a chave RSA privada em mãos a aleatoriedade não teria efeito nenhum pois para cada arquivo teríamos a chave responsável pela sua criptografia.   Por fim a extensão ".NEPHILIN" é adicionada ao arquivo aberto:             Uma coisa importante a se notar é que se a criptografia foi executada para um arquivo ou diretório específico tanto a Ransom Note quanto o wallpaper do Ransomware não são criados. Podemos observar que as funções de mapeamento de drives (que contém a criação da Ransom Note) e criação do papel de parede são ignoradas devido ao salto incondicional JMP:     E por fim...   Considerando ainda que não foram especificados arquivos e diretórios, a função responsável por criar a imagem do papel de parede é chamada. Há várias funções aqui e estas utilizam funções gráficas do Windows para editar a imagem em questão:     Uma das funções chamadas nesta função responsável por criar a imagem é justamente a função de decoda o base64 da Ransom Note, pois o que é escrito no papel de parede é a mesma coisa da Ransom Note. Após várias funções gráficas para preparar a imagem o arquivo é finalmente criado em %TEMP%, com nome god.jpg e seu conteúdo é escrito no arquivo:           Após configurar a imagem como papel de parede, o malware chama sua última função, que é responsável por fechar todos os handles e contextos de criptografia ainda pendentes:     Depois disso, o processo simplesmente sai retornando 0.   Lista de exclusão:   NEPHILIN-DECRYPT.txt $RECYCLE.BIN NTDETECT.COM MSDOS.SYS IO.SYS boot.ini AUTOEXEC.BAT ntuser.dat desktop.ini CONFIG.SYS BOOTSECT.BAK program files program files (x86) windows ntldr RECYCLER bootmgr programdata appdata .dll .NEPHILIM .exe .log .cab .cmd .com .cpl .ini .url .ttf .mp3 .pif .mp4 .msi .lnk   Espero que o estudo desta análise seja proveitoso assim como foi para mim e qualquer dúvida/feedback estou à disposição!   Abraços!
    • By paulosgf
      Pessoal,
      recebi recentemente esta referência de técnicas anti-debug atualizadas por uma fonte confiável, que é a empresa Check Point.
      Não cheguei a olhar ainda, mas achei interessante de compartilhar logo com os colegas, por ser um tema de grande relevância na área de engenharia reversa.
      Abraços!
      https://research.checkpoint.com/2020/cpr-anti-debug-encyclopedia-the-check-point-anti-debug-techniques-repository/
       
×
×
  • Create New...