From 3695f289efd3783a2ca3e0e0c4da054b48a786d9 Mon Sep 17 00:00:00 2001 From: Blau Araujo Date: Sun, 18 May 2025 11:50:09 -0300 Subject: [PATCH] parcial da aula 3 --- curso/aula-03.org | 230 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 curso/aula-03.org diff --git a/curso/aula-03.org b/curso/aula-03.org new file mode 100644 index 0000000..73f8747 --- /dev/null +++ b/curso/aula-03.org @@ -0,0 +1,230 @@ +#+title: 3 -- O formato binário ELF +#+author: Blau Araujo +#+email: cursos@blauaraujo.com + + +#+options: toc:3 + +* Objetivos + +- Compreender a estrutura do formato ELF. +- Compreender a definição das seções do programa com a linguagem Assembly. +- Explorar as seções do binário com ferramentas =readelf=, =objdump= e =hexdump=. +- Relacionar o binário ELF com seu conteúdo em Assembly. + +* O que é o formato ELF + +O formato binário ELF, de /Executable and Linking Format/ (/Formato Executável +e de Ligação/) foi originalmente desenvolvido e publicado como parte da /Interface +Binária de Aplicações/ (ABI) do Unix System V Release 4 (SVR4). Desde então, +tornou-se o padrão adotado pela maioria dos sistemas /Unix-like/ para representar +arquivos objeto binários, como executáveis e bibliotecas. + +** Principais tipos de arquivos objeto + +Os arquivos objeto, criados por montadores e editores de ligações +(/link-editores/), são representações binárias de programas destinados +a serem executados diretamente por um processador. As especificações +do ELF para o Linux definem três tipos principais de arquivos objeto: + +- Arquivo relocável :: + + Contém código e dados preparados para serem ligados a outros objetos + para criar um executável ou um objeto compartilhado. + +- Arquivo executável :: + + O arquivo de um programa que pode ser executado. + +- Arquivo objeto compartilhado :: + + Contém código e dados que podem ser ligados de duas formas: com outros + arquivos relocáveis para criar um outro objeto, ou com um executável e + outros objetos compartilhados para formar a imagem de um processo. + +* Formato do arquivo + +Os arquivos objeto participam tanto da link-edição quanto da execução de +programas. Portanto, seu formato deve acomodar as estruturas necessárias +para ambas as atividades. Na link-edição, o foco está nas seções e na +tabela de cabeçalhos de seções, enquanto que, na execução, o carregador +(/loader/) utiliza os cabeçalhos do programa para mapear segmentos na +memória. + +#+begin_example + LINK-EDIÇÃO (ARQUIVO) EXECUÇÃO (MEMÓRIA) + ┌────────────────────────┐ ┌────────────────────────┐ + │ CABEÇALHO ELF │ │ CABEÇALHO ELF │ + ├────────────────────────┤ ├────────────────────────┤ + │ TABELA DE CABEÇALHOS │ │ TABELA DE CABEÇALHOS │ + │ DO PROGRAMA (OPCIONAL) │ │ DO PROGRAMA │ + ├────────────────────────┤ ├────────────────────────┤ + │ SEÇÃO 1 │ │ │ + ├────────────────────────┤ │ SEGMENTO 1 │ + │ SEÇÃO 2 │ │ │ + ├────────────────────────┤ ├────────────────────────┤ + │ ... │ │ │ + ├────────────────────────┤ │ SEGMENTO 2 │ + │ SEÇÃO N │ │ │ + ├────────────────────────┤ ├────────────────────────┤ + │ ... │ │ ... │ + ├────────────────────────┤ ├────────────────────────┤ + │ TABELA DE CABEÇALHOS │ │ TABELA DE CABEÇALHOS │ + │ DE SEÇÕES │ │ DE SEÇÕES (OPCIONAL) │ + └────────────────────────┘ └────────────────────────┘ + +#+end_example + +*Importante!* + +- O posicionamento real das tabelas de seções e do programa pode ser + diferente de como está representado nos diagramas. +- Do mesmo modo, as seções e os seguimentos não têm uma ordem específica. +- Só o cabeçalho ELF tem uma posição fixa no arquivo. +- Um segmento na memória pode conter várias seções do arquivo. + +No diagrama... + +- Cabeçalho ELF :: + + Escrito nos primeiros 52 ou 64 bytes do arquivo, o cabeçalho ELF contém + um resumo da sua organização e diversas informações, como o formato do + arquivo (32 ou 64 bits), a ordem de escrita dos bytes de dados (/little/ + ou /big endian/), o tipo do arquivo objeto (se é relocável, executável + ou compartilhado), a arquitetura do conjunto de instruções, entre outras + definições. Os primeiros 4 bytes do cabeçalho ELF contêm a assinatura do + formato, o seu /número mágico/: o byte =0x7F= seguido dos bytes dos caracteres + =E=, =L= e =F= na tabela ASCII (=45 4C 46=). + +- Seções :: + + Contêm a organização dos dados do programa para efeito da edição das + ligações no arquivo, como as instruções do código, dados globais + contantes e variáveis, símbolos, informações de relocação, etc. + +- Tabela de cabeçalhos do programa :: + + Se existir, diz ao programa como montar uma imagem do programa quando + ele for carregado na memória para execução. Logo, se o arquivo objeto + for executável, ele terá que conter uma tabela de cabeçalhos do programa, + o que é desnecessário em arquivos objeto relocáveis. + +- Tabela de cabeçalhos de seções :: + + Contém a descrição das seções do arquivo. Cada seção tem uma entrada + na tabela com informações como seu nome, seu tamanho, a partir de onde + pode ser encontrada no arquivo (/offset/), etc. Arquivos utilizados + durante a edição de ligações precisam ter a tabela de cabeçalhos de + seções, mas ela é desnecessária no caso de arquivos objeto que só + serão ligados dinamicamente em tempo de execução. + +* Seções especiais + +Várias seções de um arquivo ELF são predefinidas para conter informações +de controle utilizadas pelo sistema operacional. Na pŕática, programas +executáveis são formados vários arquivos objeto e bibliotecas vinculados +através do processo de ligação, que pode ser: + +- *Estática:* Vários arquivo objeto são combinados em um só arquivo executável. +- *Dinâmica:* O objeto executável é ligado na memoria, em tempo de execução, + com objetos compartilhados e bibliotecas disponíveis no sistema. + +No fim das contas, o resultado será sempre um programa completo na memória, +a diferença está em quando o objeto executável é construído e em quem +resolve e processa as ligações. + +No GNU/Linux: + +- *Ligações estáticas:* Processadas pelo editor de ligações (=ld=, da suíte + GNU Binutils). +- *Ligações dinâmicas:* Processadas pelo carregador e ligador dinâmico do + sistema (=ld-linux=, da =glibc=). + +Seja a ligação realizada estaticamente, durante a construção do executável, +ou dinamicamente, no momento da execução, o correto processamento das +ligações depende da organização interna do arquivo ELF. Essa organização é +descrita por suas seções especiais, entre as quais podemos destacar: + +| Seção | Descrição | +|---------------+----------------------------------------------------------------------------------------------------------------------------------------| +| =.bss= | Contém dados globais não inicializados ou inicializados com zero; ocupa espaço na memória, mas não ocupa espaço no arquivo executável. | +| =.data= | Contém dados globais inicializados; ocupa espaço tanto no arquivo quanto na memória. | +| =.rodata= | Contém dados que não podem ser alterados (/read only/), geralmente usada para constantes e strings literais. | +| =.text= | Seção que contém o código executável do programa (instruções da CPU). | +| =.symtab= | Tabela de símbolos completa, usada pelo ligador e depuradores para localizar símbolos. | +| =.strtab= | Tabela de strings que armazena os nomes dos símbolos referenciados em =.symtab=. | + +* Tipos de segmentos + +Na execução de um programa ELF, o sistema operacional utiliza a Tabela de +Cabeçalhos do Programa para saber quais partes do arquivo devem ser carregadas +na memória e como tratá-las. Cada entrada nessa tabela descreve um segmento +que representa uma região de interesse para o carregador, como código do +programa, seus dados, informações de ligação dinâmica e o caminho do carregador +e ligador dinâmico. Esses segmentos são identificados por tipos padronizados, +cada um com uma finalidade específica no processo de carregamento e execução +do programa. + +Aqui estão alguns tipos de segmentos: + +| Tipo | Descrição | +|--------------+---------------------------------------------------------------------------| +| =LOAD= | Segmento que deve ser carregado na memória, contendo código ou dados. | +| =INTERP= | Indica o caminho do carregador dinâmico (=ld-linux=) para execução. | +| =DYNAMIC= | Contém informações para ligação dinâmica, como símbolos e dependências. | +| =GNU_STACK= | Define permissões da pilha (stack), como se pode ou não ser executável. | +| =NOTE= | Armazena metadados usados pelo sistema operacional. | +| =PHDR= | Contém a própria Tabela de Cabeçalhos do Programa, usada por depuradores. | +| =GNU_EH_FRAME= | Informações para suporte à pilha de exceções (C, C++, etc.). | +| =GNU_RELRO= | Segmento de dados que será tornado somente leitura após inicialização. | + + +** Exemplo de programa mínimo em Assembly + +#+begin_src nasm :tangle elf_min.asm +section .text + global _start + +_start: + mov rax, 60 + xor rdi, rdi + syscall +#+end_src + +** Compilação + +#+begin_src sh +nasm -f elf64 -o elf_min.o elf_min.asm +ld -o elf_min elf_min.o +#+end_src + +** Inspeção do ELF + +#+begin_src sh +file elf_min +readelf -h elf_min +readelf -S elf_min # Seções +readelf -l elf_min # Segmentos (program headers) +objdump -d elf_min +hexdump -C elf_min | less +#+end_src + +** Versão em C para comparação + +#+begin_src C :tangle elf_min.c +int main() { + return 0; +} +#+end_src + +** Exercícios + +1. Compare os headers do binário gerado em C com o de Assembly. +2. Use `readelf -x .text` para inspecionar o código de máquina. +3. Modifique o binário com `hexedit` para alterar manualmente um byte do código. +4. Gere um programa com `.data` e `.bss` e localize essas seções no ELF. + +** Referências +- man 5 elf +- https://refspecs.linuxfoundation.org/elf/elf.pdf +- https://wiki.osdev.org/ELF