Ir para conteúdo
  • Cadastre-se

Fernando Mercês

Administradores
  • Total de itens

    565
  • Registro em

  • Última visita

Tudo que Fernando Mercês postou

  1. Fernando Mercês

    Desafios suicidas x jogos sombrios

    Gostaria de divulgar aqui também o estudo sobre os desafios suicidadas ("Baleia Azul", etc) e jogos "de temática sombria" que publiquei no início do mês pela Trend Micro. Como falei no vídeo que publicamos no canal Papo Binário, é um tema sobre o qual gostaria de ter mais informações sobre, ouvir especialistas, etc. Recomendo a leitura para todos pois nunca se sabe se um amigo ou vizinho tem um filho(a) numa situação parecida. Qualquer feedback é muito bem vindo! 👍
  2. Fernando Mercês

    AnalyseMe - Nível 03

    Valeu, galera. Muito legais as análises! Alguém analisou a função que decripta as strings? Conseguiriam fazer, em Python ou em qualquer outra linguagem de programação, um decrypter? 🙂 Abraços, Fernando
  3. Fernando Mercês

    AnalyseMe - Nível 03

    Salve, pessoal! Perdoem o atraso, mas aqui está o AnalyseMe-03, o quarto da série (começou com o nível 00). Lembra de postar a reposta com a tag spoiler, pra não dar a resposta de cara pra quem quer tentar. 😉 Esse tem umas surpresinhas. hehe Em tempo, podem dar feedback do que estão achando da série? Tá legal? Muito fácil? Muito difícil? Queremos saber. Olha o binário aí e manda seus comentários por favor! Grande abraço e boa sorte! AnalyseMe-03.exe
  4. Fernando Mercês

    Boletins semanais

    Pessoal, o que estão achando dos boletins semanais? Estão ajudando? Falta algo? Abraços!
  5. Fernando Mercês

    Comparando executáveis

    Saudações, leitores do Mente Binária! Hoje me deu vontade de falar sobre uma tarefa que eventualmente preciso fazer na empresa onde trabalho, que é a de verificar as diferenças entre arquivos executáveis, normalmente de Windows, também conhecidos por executáveis PE. Há vários usos ao comparar binários. É possível avaliar o que mudou na versão atual de um software em relação à anterior, descobrir o que muda em cada sample diferente de uma mesma família de malware, etc. Esses dias mesmo me foi pedido que verificasse a diferença entre 6 arquivos maliciosos, que compartilho abaixo como fiz. Reconhecimento básico Os arquivos que recebi tinham seu hash SHA-256 como nome. A primeira coisa que fiz foi checar seu tipo (usando comandos do macOS, mas o Linux tem comandos similares): $ file * fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04: PE32 executable (GUI) Intel 80386, for MS Windows fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9: PE32 executable (GUI) Intel 80386, for MS Windows fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05: PE32 executable (GUI) Intel 80386, for MS Windows ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd: PE32 executable (GUI) Intel 80386, for MS Windows ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640: PE32 executable (GUI) Intel 80386, for MS Windows ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e: PE32 executable (GUI) Intel 80386, for MS Windows Só para garantir, também chequei o SHA-256 deles e realmente bateu com o nome, o que era esperado: $ shasum -a256 * fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e PS.: No Linux o comando seria sha256sum ao invés de shasum -a256. O próximo passo foi checar o tamanho deles: $ wc -c * 396973 fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 396973 fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 396973 fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 396973 ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd 396973 ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 396973 ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e 2381838 total Aqui apresentou-se um caso atípico: os binários possuem exatamente o mesmo tamanho! Já pensei que havia grandes chances de as diferenças entre eles serem mínimas: provavelmente algo usado pelo autor do malware só para "mudar o hash" na tentativa de evitar que os antivírus detectem os arquivos idênticos, por exemplo. Essa tentativa é na verdade frustrada visto que, ao contrário do que muitos pensam, os antivírus não detectam malware por hash normalmente, já que isso seria muito custoso do ponto de vista do desempenho (seria preciso ler todos os bytes do arquivo!) e também seria muito fácil tornar um novo arquivo indetectável - bastaria alterar um único byte para um hash final completamente diferente. Comparação de estrutura Se estivéssemos tratando arquivos de texto, poderia simplesmente usar o comando diff, mas o assunto aqui é PE, então algo interessante de verificar é sua estrutura, que consiste basicamente em cabeçalhos, localizados antes das seções. Se você não sabe do que estou falando, recomendo os seguintes recursos: Posts do @Leandro Fróes sobre o formato PE e suas referências. Capítulo sobre PE do livro Fundamentos de Engenharia Reversa. Aulas 5 e 6 do CERO, nosso Curso de Engenharia Reversa Online em vídeo. Digitar "PE executable" no Google ler o que curtir. Depois dessa imersão no mundo dos executáveis PE, não tenho dúvidas de que você vai se apaixonar por eles também! 😍 Voltando à comparação, o que eu quero dizer com estrutura? Bem, os valores dos campos dos cabeçalhos. Por exemplo, para ver o cabeçalho COFF de um arquivo PE, usei o readpe, parte do kit de ferramentas pev: $ readpe -h coff fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 COFF/File header Machine: 0x14c IMAGE_FILE_MACHINE_I386 Number of sections: 5 Date/time stamp: 1401620468 (Sun, 01 Jun 2014 11:01:08 UTC) Symbol Table offset: 0 Number of symbols: 0 Size of optional header: 0xe0 Characteristics: 0x102 Characteristics names IMAGE_FILE_EXECUTABLE_IMAGE IMAGE_FILE_32BIT_MACHINE Mas não, não usei o pev por saudosismo! A ideia de ter uma saída em texto da estrutura desses binários é depois usar o comando diff para compará-las. A primeira coisa que precisei então foi gerar um .txt contendo toda a estrutura, e não só o cabeçalho COFF, para cada um dos arquivos. Uma repetição em bash dá conta do recado: $ ls -1 readpe_output_* readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt Eu usei o readpe sem nenhuma opção, assim ele imprime todos os cabeçalhos, incluindo os de seções. Só pra começar fiz um diff do primeiro para o segundo e não houve qualquer saída, ou seja, a estrutura dos arquivos eram idênticas! E eram mesmo: $ wc -c readpe_output_* 21627 readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt 21627 readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt 21627 readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt 21627 readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt 21627 readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt 21627 readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt 129762 total $ md5 !$ md5 readpe_output_* MD5 (readpe_output_fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 MD5 (readpe_output_ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e.txt) = 05b36b89b1165b3d619bee16f8a1d7f7 Os hashes MD5 da saída em texto da estrutura de todos os arquivos batem. Eles são mesmo iguais estruturalmente! Passado o choque, percebi que teria que comparar o conteúdo das seções (código, dados, talvez resources, etc). Aí fui obrigado a inicializar minha VM do Janelas mesmo... Comparação do conteúdo das seções Existem alguns softwares que trabalham com PE e possuem funções de comparação de dois executáveis. Eu costumava usar o Cold Fusion (um antigo gerador de patch) pra isso, mas ele tem alguns bugs que me impediram. Achei a mesma função no Stud_PE, mas ele localiza arquivos por extensão na janela de comparação, então renomeei o primeiro e o segundo arquivo que tinha para a.exe e b.exe respectivamente. Ao abrir o a.exe no Stud_PE, usei o botão "File Compare", selecionei o método "Binary", setei o "Starting from" pra "Raw" e cliquei em "Compare": Se você não entendeu por que fiz isso, volte uma casa ou leia os tutorias de PE que indiquei. Ou pergunte que eu falo. 😍 Bem, entre esses dois caras então havia 9 bytes que o diferenciavam e eu já tinha os offsets a partir do início do arquivo. Agora é descobrir em que seção eles estavam no PE, o que são, o que comem e como eles vivem. 😎 Descobrindo como as diferenças são usadas Abri o executável no x64dbg (na verdade no x32dbg, já que este binário é de 32-bits) mas percebi que o entrypoint estava no endereço 013706AA. Como o ImageBase deste binário é 00400000, percebi que o ASLR estava habilitado e, antes de continuar , desabilitei-o com o DIE, como mostro neste vídeo rápido no canal Papo Binário: Antes de reabrir o binário no x32dbg, convém lembrar que eu tinha um offset e precisava convertê-lo para endereço virtual (VA). Isso é feito com o que alguns analisadores de PE chamam de FLC (File Location Calculator). O DIE tem, o Stud_PE tem e o pev também tem, com a ferramenta ofs2rva: $ ofs2rva 0x4c451 a.exe 0x4dc51 Mas pra não você não me acusar de saudosismo de novo, vou mostrar no Stud_PE 😄 Percebe que o Stud_PE já diz que este byte pertence à seção .rdata, o que à esta altura você já sabe, caso tenha feito o trabalho de casa de estudo do PE, que é provavelmente uma seção de dados somente-leitura, então há grandes chances de nossa sequência diferentona pertencer à uma string constante, por exemplo. Fui ver no debugger como é que tava a festa. Abri o a.exe lá e dei um Ctrl+G no Dump pra ir pro endereço 44DC51: De fato tinha uma string lá: zuk0KRrGrP, mas ela na verdade começava em 44DC44 e pra saber quando ela era usada no malware, coloquei um breakpoint de hardware no acesso ao byte, que é o primeiro da string e cheguei à conclusão de que, como o nome sugere, é realmente uma string de identificação da campanha do malware, sempre no mesmo offset (calculei de novo usando FLC). Agora foi só ver a dos outros e novamente recorri à uma ferramenta do pev (💚), a pestr: $ for i in *; do echo $i; pestr -so $i | grep 0x4c444; echo; done fdba340bb35635934aa43b4bddd11df31f2204e73394b59756931aa2f7f59e04 0x4c444 .rdata identifierStrzuk0KRrGrP fdf3060eb9c39b1a2be168b1ac52c2f80171394e73fe03c4e0c57911cb9358a9 0x4c444 .rdata identifierStrAR0U4hr1wW fedf9d9815b3d0ad28e62f99d5dcf92ec0f5fcb90135b4bdc30bb5709ab9ff05 0x4c444 .rdata identifierStrswEYVkFWeg ff2f1be6f64c91fa0a144cbc3c49f1970ba8107599d5c66d494ffb5550b0f7fd 0x4c444 .rdata identifierStrKXaUzlBDIj ff53c7ba285ffdc2c29683bb79bb239ea59b3532f8b146523adf24d6d61fc640 0x4c444 .rdata identifierStrv91TJ5c3Lr ffee504e292a9f3ae6c439736881ebb314c05eac8b73d8b9c7a5a33605be658e 0x4c444 .rdata identifierStrOzJnvFQy2U Bom, daí o céu é o limite. Dá pra criar assinatura, criar um script pra extrair esse ID da campanha, enfim, missão cumprida. FAQ 1. Por que você não utilizou só um comparador de arquivos qualquer, que compara os bytes em hexadecimal? Eu queria saber exatamente onde estavam as diferenças entre os arquivos, se na estrutura ou não. Em caso negativo, é código? Se sim, que código? Que faz o que? São dados? Usados onde? Em qual seção? Um editor hexadecimal ignorantão não me daria isso. Além disso, se os arquivos fossem diferente estruturalmente, ou em tamanho, eu queria saber antes, pra não perder tempo analisando diferenças de bytes hexa que eu não sei o que é. 2. Existem softwares para comparar binários PE muito mais poderosos, como o BinDiff. Por que caralhas você não o usou? O BinDiff é pra comparar código. Minha diferença estava nos dados. Além disso, o BinDiff e seus amigos traduzem o Assembly original do binário para uma linguagem intermediária própria e comparam lógica, não instruções. É bem fodão, mas não me atendia neste caso, afinal eu já sabia que os binários eram idênticos em funcionalidade. Só queria saber onde estava a diferença exata. 3. Percebi pela screenshot do Stud_PE que ele também compara a estrutura dos arquivos PE, então todo aquele processo com o readpe foi à toa? Sim, foi só pra Inglês ver. Não, brincadeira! O Stud_PE compara os cabeçalhos COFF, Optional e os diretórios de dados somente. O readpe imprime todos os cabeçalhos, incluindo todas as seções mais os imports. É outro nível, moleque! 😏 4. E quanto à executáveis ELF? O título não fala somente de PE propositalmente, já que a mesma técnica pode ser usada para arquivos ELF, só mudando os programas (readelf, etc). Por hora é só. Se você deixar sua análise abaixo ou quiser fazer um comentário/pergunta, ficarei muito grato. Considera apoiar a gente também vai. 💚
  6. Fernando Mercês

    Jogo em C - migração

    Cara, que coisa legal! Sempre quis fazer um jogo, mas é um sonho não realizado. 😁 Sobre a conio2.h, se quiser portar, recomendo a ncurses. Seu jogo vai inclusive rodar no Unix, Linux, BSD's, etc. No Windows também, via Cygwin. Mas, você vai alterar o código todo. rs Mas se quiser fazer gráfico mesmo, talvez o @augustomoreira, que falou sobre desenvolvimento de jogos neste tópico, possa ajudar? 🙂 Parabéns! Achei muito maneiro!
  7. Fernando Mercês

    Vacina: Vírus atalho

    @Aof pode compartilhar sim. Só deixar claro que é um vírus e comprimir com a senha "infected" (padrão na indústria). 😉
  8. Fernando Mercês

    0right, Let's Talk About x86 Assembly Language: Windows Internals

    Esta será a segunda aula do Thiago Peixoto em sua série 0right, Let's Talk About x86 Assembly Language, que vai rolar ao vivo na terça, dia 18 de Dezembro de 2018 no canal Papo Binário. Marca presença e nos vemos lá!
  9. Fernando Mercês

    AnalyseMe - Nível 00

    Boa, @Euler Neto. Uma pergunta adicional seria especificar o valor literal dessa constante (ERROR_ACCESS_DENIED). Abraço!
  10. Fernando Mercês

    AnalyseMe - Nível 00

    Que maneiro @rcimatti! Obrigado mesmo pela análise. Curta e precisa. =) @Aof não tem nenhuma "pegadinha" não. É só isso mesmo. Este binário é super simples, justamente por ser o primeiro nível dos desafios. A ideia é ir dificultando nos próximos, pouco a pouco. Abraços!
  11. Fernando Mercês

    Curso de Engenharia Reversa Online (CERO)

    O que é Engenharia Reversa? Engenharia reversa de software é a técnica para entender como um trecho de código funciona sem possuir seu código-fonte. É aplicável em diversas áreas da tecnologia como: Análise de malware Reimplementação de software e protocolos Correção de bugs Análise de vulnerabilidades Adição/Alteração de recursos no software Proteções anti-pirataria Alguns termos e abreviações para a engenharia reversa incluem: RCE (Reverse Code Engineering), RE, e reversing. Como funciona? Quando um programa tradicional é construído, o resultado final é um arquivo executável que possui uma série de instruções em código de máquina para que o processador de determinada arquitetura possa executar. Com ajuda de software específicos, profissionais com conhecimentos dessa linguagem (em nosso caso, Assembly) podem entender como o programa funciona e, assim, estudá-lo ou até fazer alterações no mesmo. O treinamento O CERO (Curso de Engenharia Reversa Online) é um treinamento básico gratuito publicado no nosso canal no YouTube Papo Binário, graças ao suporte dos nossos apoiadores. A primeira fase do treinamento está completa e as aulas publicadas estão abaixo. Aulas publicadas Aula 0 - Como funciona a Engenharia Reversa Aula 1 - Sistemas de Numeração Aula 2 - Arquivos Aula 3 - Arquivos binários Aula 4 - Strings de texto Aula 5 - Executável PE - Apresentação Aula 6 - Executável PE - Seções e endereçamento Aula 7 - Executável PE - Imports Table Aula 8 - Executável ELF - Apresentação Aula 9 - Executável ELF - Símbolos, PLT e GOT Aula 10 - Win32 API Aula 11 - Linux syscalls Aula 12 - Assembly - Instruções e registradores Aula 13 - Assembly - Repetições e saltos Aula 14 - Assembly - Convenções de chamada de função Aula 15 - Funções e pilha Aula 16 - Breakpoints de software Aula 17 - Quebrando o crackme do Cruehead (Parte 1) Aula 18 - Quebrando o crackme do Cruehead (Parte 2) Aula 19 - Compressão de executáveis Aula 20 - Descompressão e reconstrução da IAT Aula 21 - Breakpoints de memória Aula 22 - Rastreando instruções (tracing) Aula 23 - Strings ofuscadas Aula 24 - Anti-debug Pré-requisitos Máquina virtual com Ubuntu Máquina virtual com Windows 7 Lógica de programação. Desejável assistir o treinamento gratuito Programação Moderna em C.
  12. Fernando Mercês

    Programação Moderna em C

    O que é? C é uma linguagem de programação criada na década de 60 e utilizada largamente até os dias atuais. É comum se ouvir que “metade do Universo é escrito em C” e de fato é impressionante o número de aplicações de base escritas nesta linguagem. Exemplos incluem: Linux, Apache httpd, PHP, Java, Perl, Ruby, Python e a API do Windows. Por que estudar C? Acreditamos que o estudo da linguagem C é muito benéfico para o profissional que lida com computadores, independente da área. Estudar C nos obriga a focar nas bases da computação, entender como os dados são manipulados em memória pelo sistema operacional e pelo processador, suas limitações e condições para funcionamento. Algumas vantagens de se estudar C são: Pouca coisa "vem pronta" em C, nos forçando a implementar e entender as limitações da computação atual. O programador tem controle quase total do contexto do programa. É uma linguagem comercial, principalmente na era dos embarcados. Mas C não é velho? A linguagem foi criada há muito tempo, mas continua sendo atualizada e utilizada. Basta olhar o índice TIOBE, que mede as linguagens mais em alta no mundo, para comprovar o que dissemos. A última atualização na especificação padrão foi em 2011 mas os compiladores adicionam extensões periodicamente. O gcc (GNU Compiler Collection) e o Visual Studio, da Microsoft, são bem famosos, mas há também o clang que ganhou bastante espaço recentemente. O treinamento O treinamento Programação Moderna em C aborda aspectos modernos da linguagem, bem como do ecossistema para desenvolvimento de aplicações em C, como o SO, editores de texto, IDE’s, etc. O curso está no YouTube, no nosso canal Papo Binário, sem nenhum custo. São 20 aulas em 23 vídeos. Segue a lista: Aula 0: Preparando o ambiente Aula 1: Funções main() e printf() Aula 2: Variáveis booleanas e do tipo char Aula 3: Variáveis do tipo int Aula 4: Variáveis do tipo float Aula 5: Arrays Aula 6: Operadores aritiméticos Aula 7: Operadores lógicos Aula 8: Operadores bit-a-bit Aula 9: Condicional if Aula 10: Repetições (Parte 1/2) Aula 10: Repetições (Parte 2/2) Aula 11: Ponteiros (Parte 1/2) Aula 11: Ponteiros (Parte 2/2) Aula 12: Indexação de arrays e ponteiros Aula 13: Alocação dinâmica de memória Aula 14 - Estruturas e Uniões Aula 15 - Funções Aula 16 - Macros Aula 17 - Escopo e classes de armazenamento Aula 18 - Projeto readpe (Parte 1/3) Aula 19 - Projeto readpe (Parte 2/3) Aula 20 - Projeto readpe (Parte 3/3)
  13. Fernando Mercês

    Desativando LD_PRELOAD no Linux

    O preloading é um recurso suportado pelo runtime loader de binários ELF implementado na glibc (GNU C Library), mais especificamente no arquivo rtld.c. Ele consiste em carregar uma biblioteca antes de todas as outras durante o carregamento de um programa executável. Assim é possível injetar funções em programas, inspecionar as funções existentes, etc. Por exemplo, considere o programa ola.c abaixo: #include <stdio.h> void main() { printf("ola, mundo do bem!"); } Ao compilar e rodar, a saída é conforme o esperado: $ gcc -o ola ola.c $ ./ola ola, mundo do bem! A função printf() foi utilizada com sucesso pois este binário foi implicitamente linkado com a glibc graças ao gcc. Veja: $ ldd ola linux-vdso.so.1 (0x00007ffe4892b000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8a3a2dd000) /lib64/ld-linux-x86-64.so.2 (0x00007f8a3a692000) E portanto a função printf() é resolvida. Até aí nenhuma novidade. Agora, para usar o recurso do preloading, temos que criar uma biblioteca, que será carregada antes da glibc (libc6). A ideia é fazer com o que o binário chame a nossa printf() e não a da glibc. Isso pode ser chamado de usermode hook (incompleto, porém, já que eu repassei o argumento para a função puts() ao invés da printf() original da glibc). Considere o código em hook.c: #include <stdio.h> int printf(const char *format, ...) { puts("hahaha sua printf tah hookada!"); return puts(format); } O protótipo da printf() é o mesmo do original (confira no manual). Eu não reimplementei tudo o que precisaria para ela aqui, somente o básico para ajudar na construção do artigo. E como expliquei antes, o hook não está completo uma vez que eu passo o que recebo na minha printf() para a função puts() da glibc. O ideal seria passar para a printf() original mas para isso eu precisaria buscar o símbolo, declarar um ponteiro de função, etc. E o assunto desde artigo não é hooking de funções. Por hora vamos compilar a biblioteca: $ gcc -shared -fPIC -o hook.so hook.c $ ldd hook.so linux-vdso.so.1 (0x00007ffffadb8000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f011dfbc000) /lib64/ld-linux-x86-64.so.2 (0x00007f011e572000) E agora precisamos instruir o loader a carregá-la antes de todas as outras quando formos executar o nosso programa (ola). Há pelo menos duas formas de acordo com a documentação oficial: Definir uma variável de ambiente LD_PRELOAD contendo o endereço de uma ou mais bibliotecas para serem carregadas. Colocar o path de uma ou mais bibliotecas num arquivo /etc/ld.so.preload (caminho e nome são fixos aqui). Então vamos testar. Primeiro uma execução normal, depois com a variável LD_PRELOAD setada e finalmente com o recurso do arquivo /etc/ld.so.preload: ## Execução normal $ ./ola ola, mundo do bem! ## Com caminho em variável de ambiente $ export LD_PRELOAD=$PWD/hook.so $ ./ola hahaha sua printf tah hookada! ola, mundo do bem! ## Com caminho em arquivo $ unset LD_PRELOAD # echo $PWD/hook.so > /etc/ld.so.preload $ ./oi hahaha sua printf tah hookada! hello world Percebe o perigo? Não é à toa que existem vários malware para Linux utilizando este recurso. Alguns exemplos são os rootkits Jynx, Azazel e Umbreon. Além disso, algumas vulnerabilidades como a recente CVE-2016-6662 do MySQL dependem deste recurso para serem exploradas com sucesso. É razoável então um administrador que não utilize este recurso num servidor em produção querer desabilitá-lo, certo? Desabilitando o preloading Não há mecanismo no código em questão da glibc que permita desabilitar este recurso. Pelo menos eu não achei. Uma saída é alterar os fontes e recompilar, mas a glibc demora tanto pra ser compilada que eu desisti e optei por fazer engenheira reversa no trecho necessário e verificar quão difícil seria um patch. Analisando o fonte do rtld.c fica fácil ver que a função do_preload() retorna o número de bibliotecas a serem carregadas no preloading. Primeiro a checagem é feita na variável de ambiente LD_PRELOAD: O número de bibliotecas é armazenado na variável npreloads., que mais tarde alimenta uma repetição para de fato carregar as bibliotecas. Mais abaixo, o vemos que o trecho de código que busca o arquivo /etc/ld.so.preload também usa a do_preload(): Sendo assim veio a ideia de encontrar essa função no loader (no meu caso /lib64/ld-linux-x86-64.so.2 – mas pode estar em /lib para sistemas x86 também) e patchear lá diretamente. PS.: Apesar de o código ser parte da glibc, a biblioteca do loader é compilada separadamente e tem um nome tipo ld-linux-$ARCH.so.2, onde $ARCH é a arquitetura da máquina. No meu caso, x86-64. Fiz uma cópia do arquivo /lib64/ld-linux-x86-64.so.2 para o diretório $HOME para começar a trabalhar. Pelo visto ela é compilada sem os símbolos, o que elimina a hipótese de achar a função por nome de forma fácil: $ nm ld-linux-x86-64.so.2 nm: ld-linux-x86-64.so.2: no symbols Sem problemas. Com o HT Editor, um editor de binários com suporte a disassembly, abri o arquivo e busquei pela string “/etc/ld.so.preload” já que ela é fixa na função, que deve referenciá-la. A ideia foi chegar no trecho de código que chama a função do_preload(). Os passos são: Abrir a biblioteca no hte: $ hte ld-linux-x86-64.so.2 No hte, facilita se mudarmos o modo de visualização para elf/image com a tecla [F6]. Depois é só usar [F7] para buscar pela string ASCII /etc/ld.so.preload: Após achar a string percebemos que ela é referenciada (; xref) em 4 lugares diferentes. Um desses trechos de código também deve chamar a função do_preload() que é a que queremos encontrar. Depois de analisar cada um deles, percebemos que tanto na r4294 quando na r4302 logo depois da referência à string tem uma CALL para uma função em 0xae0 que ao seguir com o hte (apertando [ENTER] no nome dela) é mostrada abaixo: Se comparamos com o código da função do_preload() vemos que se trata dela: A ideia é forçar que ela retorne 0, assim quando ela for chamada seja pelo trecho de código que carrega as bibliotecas a partir da variável LD_PRELOAD ou pelo trecho responsável por ler o arquivo /etc/ld.so.preload, ela vai sempre retornar 0 e vai fazer com que o loader não carregue as bibliotecas. Para isso, desça até o trecho de código do salto em 0xb37. Perceba que ele salta para 0xb56 onde o registrador EAX é zerado com um XOR, e depois o registrador AL (parte baixa de AX, que por sua vez é a parte baixa de EAX) é setado para 1 pela instrução SETNZ caso a condição em 0x58 não seja atendida (linha 675 no código-fonte). Só precisamos fazer com que esta instrução SETNZ em 0xb5e não seja executada para controlar o retorno da função. Ao pressionar [F4], entramos no modo de edição. Há várias maneiras de fazer com que esta instrução em 0xb5e não execute, mas vou fazer a mais clássica: NOPar seus 3 bytes. No modo de edição, substitua os bytes da instrução SETNZ AL (0f 95 c0) por 3 NOP’s (90 90 90), ficando assim: Dessa forma, o EAX é zerado em 0xb56, a comparação ocorre em 0xb58 mas ele não é mais alterado, tendo seu conteúdo zerado até o retorno da função. [F2] para salvar. Agora para testar vou usar duas técnicas combinadas. A primeira é de declarar uma variável de ambiente só para o contexto de um processo. A outra é de usar o loader como se fosse um executável (sim, ele pode receber o caminho de um binário ELF por parâmetro!). Veja: $ LD_PRELOAD=$PWD/hook.so ./ld-linux-x86-64.so.2 ./ola Inconsistency detected by ld.so: rtld.c: 1732: dl_main: Assertion `i == npreloads' failed! Para nosso azar, o loader checa o número de funções a serem carregadas dentro de uma repetição, fora da função do_preload(). Precisamos achar essa confirmação (assertion) para patchear também. Usando a mesma técnica de buscar pela string primeiro (nesse caso busquei pela string “npreloads” exibida no erro) você chega na referência r3148: Que te leva diretamente para a repetição da assert(): Comparando com o fonte: Para o salto em 0x3134 sempre acontecer e a CALL de erro em 0x3154 não executar, resolvi patchear a instrução JZ para que sempre pule para 0x2d60. No modo de edição dá pra ver que há um JMP negativo (salto para trás) em 0x315f de 5 bytes, conforme a figura: Podemos usá-lo só para copiar o opcode. Como em 0x3134 temos 6 bytes, NOPamos o primeiro e copiamos o opcode do JMP negativo (que é 0xe9), ficando assim: Após salvar e testar, voilà: ## Com variável de ambiente $ LD_PRELOAD=$PWD/hook.so ./ld-linux-x86-64.so.2 ./ola ola, mundo do bem! ## Com arquivo # echo $PWD/hook.so > /etc/ld.so.preload $ ./ld-linux-x86-64.so.2 ./ola ola, mundo do bem! Agora se você for bravo o suficiente é só substituir o loader original para desativar completamente o recurso de preloading e ficar livre de ameaças que abusam dele. Fica também o desafio para quem quiser automatizar este processo de alguma maneira e/ou trabalhar na versão de 32-bits do loader. O Matheus Medeiros fez um script maneiro para automatizar o patch! Valeu, Matheus! Patches de código e recompilação seriam melhores opções, de fato, mas quis mostrar uma maneira usando engenharia reversa por três motivos: Se automatizada, pode ser mais fácil de ser colocada em prática em um ambiente em produção. Recompilar a glibc demora muito. Se alguém souber de uma maneira de recompilar somente o loader, por favor, me avise! Engenharia Reversa é divertido.
  14. Fernando Mercês

    Gerador de licença hexadecimal de 32

    Bem vindo, Erick! Seria legal postar como sombrakey falou. Eu tentei fazer um código simples aqui e saiu isso: #!/usr/bin/env python3 s = 12345 while len(str(format(s, 'x'))) < 32: s = s * 3 + 9 print(format(s, 'x')) Funciona. Para o login 12345 a saida foi 174192b6bdc3131722ea52cb13c21a9d. E claro, você pode alterar o algoritmo pra fazer a conta que quiser. Ele vai aumentando o número até que o tamanho do resultado em hexa seja 32. Mas essa lógica só gera um único número válido. Não sei se é isso o que você quer, mas pode ser um ponto de partida. Daí seria preciso aprender a programar - e aprender Python - pra poder continuar, mas espero que seja possível começar. 🤓 Abraço!
  15. Fernando Mercês

    crackme

    Tem uns aqui mesmo, Bruno, nessa área de desafios. ;)
  16. Fernando Mercês

    Desativando LD_PRELOAD no Linux

    Tudo bem, Fabiano e você? Como sempre, ótimas discussões. 🙂 O recurso é realmente perigoso mas serve em situações onde se é preciso debugar software, principalmente quando não se tem o código-fonte de um programa já compilado. Com este recurso é possível, por exemplo, saber exatamente o que uma certa função recebe durante a execução do programa, afim de depurá-la. Não sei mais que isso sobre a decisão dos programadores do projeto de GNU de criar/manter isso. Só sei que é explorado por atacantes. Já sobre o ld-linux, passar um binário linkado dinamicamente pra ele como argumento funciona porque ele é justamente o loader e linker dinâmico de binários no Linux (dá um man ld.so pra ver), ou seja, ele carrega o binário em memória e resolve as dependências de bibliotecas e funções que ele precisa, depois o executa. Esse processo não é necessário para binários compilados estaticamente, já que não há dependências a serem resolvidas e por isso binários estáticos "não dependem de ninguém" e o ld-linux nem consegue carregá-los. Pensei aqui numa maneira interessante de aprofundar este estudo: gerar um core dump neste segfault e estudá-lo no gdb, afim de descobrir exatamente quando ele acontece e por qual motivo, programaticamente falando (do código do ld-linux). Mas enfim, o comportamento tá normal. Exceto que, na minha ignorância, uma mensagem de erro seria de bom grado. 🤓 Um abraço!
  17. Fernando Mercês

    Editar/criar conteúdo do livro

    Pois é, ainda não consegui migrar o livro para o Github mas vou trabalhar nisso em breve. Por hora, vou buscar implementar suas sugestões, @Lucas Rodrigues e volto a informar aqui. 😉 Muito obrigado!
  18. Fernando Mercês

    QuickUnpack

    Versão 3.4

    20 downloads

    Também conhecido por QUnpack, este unpacker genérico de 32-bits (precisa de Windows de 32-bits pra rodar) tem suporte a mais de 1000 packers/protectors diferentes.
  19. Fernando Mercês

    Stud_PE

    Versão 2.6.1.0

    20 downloads

    Analisador de PE clássico, que teve sua última versão publicada em 2002. Seu site oficial é http://www.cgsoftlabs.ro/ Apesar de velhinho, tem alguns recursos interessantes, como a comparação de estrutura de binários usada no artigo Comparando executáveis.
  20. Fernando Mercês

    VMUnpacker

    Versão 1.3

    14 downloads

    Versão 1.3 deste unpacker genérico (não é pro VMProtect) em inglês e chinês. Já vi a versão 1.5 em chinês somente e a versão 1.6 (a última) ainda não conseguimos encontrar. Caso encontre, sobe aqui pra gente! 😉
  21. Fernando Mercês

    Awesome lists

    Conheci mais algumas! https://github.com/wtsxDev/reverse-engineering https://github.com/onethawt/reverseengineering-reading-list E pra samples de malware: https://github.com/greg5678/Malware-Samples
  22. Fernando Mercês

    Coordenador de SI em BH

    Detalhes em http://site.vagas.com.br/v1780357 😉
  23. Fernando Mercês

    Especialista em SI - São Paulo

    Especialista de Segurança da Informação, p/ Pinheiros, vaga: PJ, Perfil: experiencia na ferramenta FORTIFY, JAVA, com certificação na área. currículos: talent EM domvs.com.br
  24. Fernando Mercês

    Programadores iniciantes x experientes

  25. Fernando Mercês

    Essa cebola não vai me fazer chorar

×