Inspetor de binários ELF
Lê um binário ELF do mesmo jeito que o readelf, direto dos bytes e inteiramente no seu navegador. O cabeçalho informa o tamanho de palavra e a ordem de bytes, o OS/ABI, a arquitetura, o ponto de entrada e se o arquivo é um objeto realocável, um executável comum, um executável independente de posição ou uma biblioteca compartilhada — distinção que o cabeçalho sozinho não faz, porque um PIE e um .so são ambos DYN e só o interpretador ou a flag DF_1_PIE os separa. Os cabeçalhos de programa listam o que o carregador mapeia, e o array dinâmico dá o caminho do interpretador, cada biblioteca em DT_NEEDED, o SONAME sob o qual uma biblioteca se publica e qualquer RPATH ou RUNPATH gravado no arquivo; vale conferir esse último em qualquer binário que você não tenha compilado, porque ele muda onde o carregador procura. A linha de endurecimento responde ao que o checksec responde, a partir dos mesmos lugares: PIE pelo tipo e por DF_1_PIE, NX conforme PT_GNU_STACK seja gravável e executável, e RELRO como nenhum, parcial ou completo conforme haja PT_GNU_RELRO e BIND_NOW. Sem símbolos quer dizer que o arquivo não tem SHT_SYMTAB, que é o que o strip remove; a tabela de símbolos dinâmicos permanece, então uma biblioteca sem símbolos continua exportando seus nomes. Duas coisas que ele não faz: não desmonta e não diz se houve protetor de pilha ou FORTIFY_SOURCE, porque ambos exigem ler a tabela de símbolos atrás de nomes específicos, e não uma flag de cabeçalho. Arquivos big-endian e de 32 bits são lidos corretamente, então um binário ARM, MIPS ou PowerPC de um roteador ou de uma imagem embarcada abre tão bem quanto um de x86-64.
Como usar
- Solte o binário sobre a caixa: serve um executável sem extensão, um .so, um .o ou um despejo de memória.
- Leia a linha do cabeçalho para arquitetura e tipo. Executável PIE e objeto compartilhado são ambos DYN; a linha do interpretador diz qual você tem.
- Confira as etiquetas de endurecimento: PIE, NX e RELRO completo é o normal em uma compilação de distribuição, e uma etiqueta âmbar merece explicação antes de distribuir o arquivo.
- Veja Precisa de para as bibliotecas que o carregador vai procurar, e RUNPATH para qualquer diretório fora do padrão que o binário acrescenta a essa busca.
- Abra a lista de seções quando precisar de tamanhos: .text para o código, .rodata para as constantes e as seções .debug_* se a informação de depuração ficou no arquivo.
Perguntas frequentes
- Qual a diferença entre um executável PIE e uma biblioteca compartilhada? Os dois dizem DYN.
- O tipo ELF é mesmo o mesmo: código independente de posição que o carregador pode mapear em qualquer endereço. O que os separa é que um executável tem um cabeçalho de programa PT_INTERP nomeando o carregador dinâmico (em geral /lib64/ld-linux-x86-64.so.2) para o núcleo saber iniciá-lo, enquanto uma biblioteca não tem e só é carregada por outro programa. As cadeias de ferramentas atuais também marcam DF_1_PIE nas flags dinâmicas do executável, que é o que o readelf informa e o que esta ferramenta olha primeiro, recorrendo ao interpretador quando um ligador antigo deixou a flag de fora.
- Do que PIE, NX e RELRO realmente protegem?
- O PIE permite ao núcleo carregar o binário em um endereço base aleatório, de modo que o ASLR vale também para o código do próprio programa e não só para as bibliotecas; sem ele, os endereços dos gadgets são fixos e conhecidos. O NX marca a pilha como não executável, então não dá para simplesmente saltar para o shellcode injetado. O RELRO deixa as tabelas de realocação somente leitura depois da inicialização: o parcial protege as resolvidas antes do main, e o completo ainda resolve todas as funções de antemão para deixar a GOT somente leitura, fechando a clássica sobrescrita da GOT. As três são propriedades da ligação, e por isso podem ser lidas do arquivo sem executá-lo.
- Por que diz que o binário está sem símbolos se ainda vejo nomes de funções?
- Existem duas tabelas de símbolos. Sem símbolos aqui quer dizer que a SHT_SYMTAB sumiu, que é o que o strip remove e o que um depurador precisa. A tabela dinâmica, SHT_DYNSYM, precisa continuar em qualquer arquivo que exporte ou importe símbolos, senão a ligação dinâmica não funcionaria — por isso uma biblioteca sem símbolos ainda lista tudo o que exporta e um executável sem símbolos ainda lista o que importa. É por isso que o nm diz não haver símbolos enquanto o nm -D imprime uma lista.
- Ele lê um binário de outra arquitetura ou big-endian?
- Sim. O byte de classe e o de dados no início do cabeçalho dizem se o arquivo é de 32 ou 64 bits e qual ordem de bytes usa, e todos os campos seguintes são lidos através desses dois, então um binário AArch64, ARM, MIPS, RISC-V ou PowerPC big-endian é lido com a mesma exatidão de um x86-64. A arquitetura aparece pelo nome nos tipos comuns e como código bruto nos demais. O que ele não faz é dizer se o binário vai rodar na sua máquina: isso depende do núcleo, da ABI e das bibliotecas, não só do cabeçalho.
- Para que serve o Build ID?
- É um hash que o ligador guarda em uma seção de notas e que identifica exatamente aquela compilação. As distribuições o usam para casar um binário com os símbolos de depuração distribuídos à parte: o arquivo de depuração vai para /usr/lib/debug/.build-id/xx/yyyy.debug, e um depurador que receba um despejo consegue achar os símbolos certos mesmo com o binário sem símbolos. Também é um jeito confiável de saber se dois arquivos são mesmo a mesma compilação, porque o identificador muda a qualquer mudança na saída compilada.
- O binário é enviado para algum lugar?
- Não. O arquivo é lido com a File API do navegador e analisado por JavaScript na página. Nada vai para um servidor e não existe componente de servidor para onde mandar, o que aqui pesa mais do que na maioria das ferramentas: um binário que você está inspecionando pode ser justamente o que você não pode enviar. Dá para desconectar da rede depois que a página carrega e tudo continua funcionando.
Ferramentas relacionadas
Inspetor de binários Mach-O
Abra um binário de macOS ou iOS no navegador: arquiteturas de um arquivo universal, segmentos e seções, dylibs, rpaths, UUID e assinatura.
Inspetor PE: visualizador de EXE e DLL
Abra um .exe, .dll, .sys ou .efi do Windows no navegador: arquitetura, subsistema, importações, exportações, seções e se tem ASLR, DEP e CFG.
Inspetor de arquivos .class do Java
Analise um .class compilado no navegador: versão do arquivo e do Java, sinalizadores de acesso, pool de constantes, campos, métodos e dependências.
Inspetor de módulos WebAssembly
Analise um .wasm no navegador: tamanho de cada seção, importações e exportações com tipos, páginas de memória, função start e seções name e producers.
Visualizador de arquivos mbox
Divide um arquivo .mbox no navegador: limites de mensagem, cabeçalhos decodificados, estrutura MIME, tópicos e Message-ID duplicados. Nada é enviado.
Inspetor de bancos de dados SQLite
Abra um arquivo .sqlite ou .db no navegador e leia sua estrutura: tamanho de página, codificação, modo de journal e as linhas reais de cada tabela.