A Aldeia Numaboa ancestral ainda está disponível para visitação. É a versão mais antiga da Aldeia que eu não quis simplesmente descartar depois de mais de 10 milhões de pageviews. Como diz a Sirley, nossa cozinheira e filósofa de plantão: "Misericórdia, ai que dó!"

Se você tiver curiosidade, o endereço é numaboa.net.br.

Leia mais...

Informática Numaboa - Referências

O formato PE

Sab

11

Abr

2009


11:01

(10 votos, média 5.00 de 5) 


Cabeçalhos das seções

Cabeçalho MZ do DOS
Fragmento (stub) do DOS
Cabeçalho do Arquivo
Cabeçalho Opcional
Diretório de Dados
Cabeçalhos das Seções
Seção 1
Seção 2
...
Seção n

As seções são compostas por duas partes principais: primeiro, a descrição da seção (do tipo IMAGE_SECTION_HEADER) e depois os dados propriamente ditos. Desta forma, logo após os diretórios de dados, encontramos um array de cabeçalhos de seções do tipo número de seções ('NumberOfSections'), ordenado pelos RVAs das seções. Um cabeçalho de seção contém:

  • Um array de Nomes das Seções
  • Endereço Físico e do Tamanho Virtual
  • Endereço Virtual
  • Tamanho dos Dados
  • Ponteiro para os Dados
  • Ponteiro para Remanejamento
  • Características

Nomes das Seções

O primeiro componente é um array de IMAGE_SIZEOF_SHORT_NAME de 8 bytes para guardar o nome (ASCII) da seção. Se todos os 8 bytes forem usados não existe um terminador 0 (zero) para a string! O nome é tipicamente algo como ".data" ou ".text" ou mesmo ".bss". Não há a necessidade do nome ser precedido por um ponto '.' e não existem nome predefinidos (qualquer nome é aceito).

Os nomes também não têm qualquer relação com o conteúdo da seção. Uma seção de nome ".code" pode ou não conter código executável: pode perfeitamente conter a tabela de endereços de importação, pode conter código executável E a tabela de endereços de importação e até os dados inicializados.

Para achar informações nas seções, é preciso buscá-las nos diretórios de dados do cabeçalho opcional. Não se deixe influenciar pelo nome da seção e não assuma que os dados da seção estejam logo no início da mesma.

Offset 01234 56789 ABCDE FASCII
...
0000 01B0 2E 74 65 78 74 00 00 00 .text...
0000 01C0 94010000 00100000 00020000 00040000 ”...............
0000 01D0 00000000 00000000 00000000 20000060 ............ ...
0000 01E0 2E 72 64 61 74 61 00 00 C2010000 00200000 .rdata..Å.... ..
0000 01F0 00020000 00060000 00000000 00000000 ................
0000 0200 00000000 40000040 2E 64 61 74 61 00 00 00 ....@..@.data...
0000 0210 24000000 00300000 00020000 00080000 $....0..........
0000 0220 00000000 00000000 00000000 400000C0 ............@..Å
0000 0230 2E 72 73 72 63 00 00 00 60090000 00400000 .rsrc...`....@..
0000 0240 000A0000 000A0000 00000000 00000000 ................
0000 0250 00000000 400000C0 ....@..Å.........

Endereço Físico e do Tamanho Virtual

O próximo membro da IMAGE_SECTION_HEADER é a união de 32 bits do Endereço Físico ('PhysicalAddress') e do Tamanho Virtual ('VirtualSize'). Num arquivo objeto, este é o endereço para o qual o conteúdo é remanejado; num executável, é o tamanho do conteúdo. Mais uma vez, este campo não é utilizado! Há linkadores que o preenchem com o tamanho, outros com o endereço e outros ainda que o preenchem com 0. Apesar disso, os executáveis não apresentam problemas.

Endereço Virtual

Logo a seguir vem o Endereço Virtual ('VirtualAddress'), um valor de 32 bits que contém o RVA para os dados da seção quando esta estiver mapeada na RAM.

Offset 01234 56789 ABCDE FASCII
...
0000 01B0 2E 74 65 78 74 00 00 00 .text...
0000 01C0 94010000 00 10 00 00 00 02 00 00 00 04 00 00 ”...............
0000 01D0 00000000 00000000 00000000 20 00 00 60 ............ ...

No nosso exemplo, o valor encontrado é 0000 1000, ou seja, o RVA será de 4096 bytes (destacado em azul).

Tamanho dos Dados

Após o endereço virtual vêm 32 bits para os Tamanho dos Dados ('SizeOfRawData'), que nada mais é do que o tamanho dos dados da seção arredondado para cima, para o próximo múltiplo de 'FileAlignment' (alinhamento de arquivo).

No nosso exemplo, o valor encontrado é 0000 0200, ou seja, o tamanho dos dados da seção é de 512 bytes (veja acima, destacado em verde).

Ponteiro para os Dados

Segue-se o Ponteiro para os Dados ('PointerToRawData'), também de 32 bits. Este ponteiro é extremamente útil porque é o offset do início do arquivo em disco até os dados da seção. Se for 0, os dados da seção não estão contidos no arquivo e serão carregados arbitrariamente no momento da carga do programa.

No exemplo, encontramos 0000 0400, destacado acima em vermelho. Observe o endereço 0400 deste arquivo armazenado em disco:

Offset 01234 56789 ABCDE FASCII
0000 0400 6A00E887 010000A3 1C304000 E8770100 j.è‡...£.0@.èw..

Após uma longa sucessão de zeros em endereços anteriores, em 0400 inicia-se a sucessão de dados da seção .text.

Ponteiro para Remanejamento

A seguir vem o Ponteiro para Remanejamento ('PointerToRelocations') de 32 bits e o Ponteiro para Números de Linha ('PointerToLinenumbers'), também de 32 bits, o Número de Remanejamentos ('NumberOfRelocations') de 16 bits e o Número de Números de Linha ('NumberOfLinenumbers'), também de 16 bits. Todas estas informações somente são utilizadas para arquivos objeto. Os executáveis não possuem um diretório de remanejamento base especial e a informação de número de linha, se é que está presente, geralmente está localizada num segmento especial para debugging ou em qualquer outro lugar.

No exemplo, todas estas posições estão preenchidas com zeros (observe a linha 01D0 acima).

Características

O último membro dos cabeçalhos das seções é o valor de 32 bits com as Características. São um punhado de flags que descrevem como a memória das seções deve ser tratada:

NomeBitSetado (valor 1)
IMAGE_SCN_CNT_CODE5A seção contém código executável.
IMAGE_SCN_CNT_INITIALIZED_DATA6A seção contém dados que recebem um valor definido antes que a execução se inicie. Em outras palavras: os dados da seção são significativos.
IMAGE_SCN_CNT_UNINITIALIZED_DATA7A seção contém dados não inicializados que terão todos os bytes zerados antes que a execução se inicie. Este, geralmente, é o BSS.
IMAGE_SCN_LNK_INFO9A seção não contém dados de imagem e sim comentários, descrições ou outra documentação qualquer. Esta informação faz parte de arquivos objeto e pode ser a informação para o linker, como, por exemplo, as bibliotecas necessárias.
IMAGE_SCN_LNK_REMOVE11Os dados fazem parte de uma seção de um arquivo objeto que deve ser deixado de fora quando o arquivo executável for linkado. Com frequência este bit está combinado com o bit 9.
IMAGE_SCN_LNK_COMDAT12A seção contém o "common block data", que são funções de pacotes.
IMAGE_SCN_MEM_FARDATA15Existe 'far data' - significado incerto.
IMAGE_SCN_MEM_PURGEABLE17Os dados da seção podem sofrer um 'purge' - não é o mesmo que descartáveis, pois há um bit para este fim (veja abaixo). O mesmo bit, aparentemente, é usado para indicar informações de 16 bits - significado incerto.
IMAGE_SCN_MEM_LOCKED18Significado incerto - a seção não pode ser deslocada na memória? - não há informação de remanejamento?
IMAGE_SCN_MEM_PRELOAD19Significado incerto - a seção deve ser "paginada" antes do início da execução?
20 a 23Especificam um alinhamento. Não há informações disponíveis. Existe um #define IMAGE_SCN_ALIGN_16BYTES e parecidos...
IMAGE_SCN_LNK_NRELOC_OVFL24A seção contém alguns remanejamentos extendidos - significado incerto.
IMAGE_SCN_MEM_DISCARDABLE25Os dados da seção não são necessários após o início do processo. É o caso, por exemplo, das informações de remanejamento. São encontradas também para rotinas de startup de drivers e serviços que são executados apenas uma vez e para diretórios de importação.
IMAGE_SCN_MEM_NOT_CACHED26Os dados da seção não devem ir para cache. (Será que significa desligar o cache de segundo nível?)
IMAGE_SCN_MEM_NOT_PAGED27Os dados da seção não devem sair da página. Isto é interessante para drivers.
IMAGE_SCN_MEM_SHARED28Os dados da seção são compartilhados entre todas as instâncias das imagens que estiverem sendo executadas. Se forem os dados inicializados de uma DLL, por exemplo, todos os conteúdos das mesmas variáveis serão os mesmos em todas as instâncias da DLL. Note que apenas a seção da primeira instância é inicializada. Seções contendo código são sempre compartilhadas copy-on-write, isto é, o compartilhamento não funciona se houver a necessidade de fazer remanejamentos.
IMAGE_SCN_MEM_EXECUTE29O processo recebe acesso de 'execução' na memória da seção.
IMAGE_SCN_MEM_READ30O processo recebe acesso de 'leitura' na memória da seção.
IMAGE_SCN_MEM_WRITE31O processo recebe acesso de 'escrita' na memória da seção.

Analisando os últimos 32 bits do cabeçalho da seção .text, destacados em magenta logo acima, obtemos o hexadecimal 6000 0020. Abrindo-o em bits para poder analisar este valor, constatamos o seguinte:

Hexa6000 0020
Binário 1100 0000 0000 0000 0000 0000 1000 0000
Bits 31302928 27262524 23222120 19181716 15141312 111098 7654 3210

Relevante na seção .text são os seguintes bits:

  • Bit 5 = 0: A seção NÃO contém código executável.
  • Bit 7 = 1: A seção contém dados não inicializados.
  • Bit 29 = 0: O processo NÃO recebe acesso de 'execução'.
  • Bit 30 = 1: O processo recebe acesso de 'leitura'.
  • Bit 31 = 1: O processo recebe acesso de 'escrita'.

:anota: Exercícios propostos

Para este módulo, tente o seguinte:

  1. Abra os bits de Características das seções .rdata e .data do programa exemplo. Quais as diferenças entre estas seções?
  2. Abra outro programa e determine as Características das suas seções.
  3. Determine o endereço virtual das seções do programa exemplo e verifique se aponta para o início dos dados das respectivas seções.
  4. Faça o mesmo com um outro executável qualquer.

Informações adicionais