Opcional
Não parece, mas este cabeçalho é muito importante. Seu nome deve-se ao fato de que ele é opcional para arquivos objeto, mas é obrigatório em arquivos executáveis, que são o nosso foco de estudo. O tamanho desde cabeçalho não é fixo. É definido pelo campo SizeOfOptionalHeader do cabeçalho COFF, que vimos anteriormente. Sua estrutura para arquivos PE de 32-bits, também chamados de PE32, é a seguinte:
Vamos analisar agora os campos mais importantes no nosso estudo:
Magic
O primeiro campo, de 2 bytes, é um outro número mágico que identifica o tipo de executável em questão. O valor 0x10b significa que o executável é um PE32 (executável PE de 32-bits), enquanto o valor 0x20b diz que é um PE32+ (executável PE de 64-bits).
A Microsoft chama os executáveis de PE de 64-bits de PE32+ e não de PE64.
AddressOfEntryPoint
Este é talvez o campo mais importante do cabeçalho opcional. Nele está contido o endereço do ponto de entrada (entrypoint), abreviado EP, que é onde o código do programa deve começar. Para arquivos executáveis este endereço é relativo à base da imagem (campo que veremos a seguir). Para bibliotecas, ele não é necessário e pode ser zero, já que as funções de bilbioteca podem ser chamadas arbitrariamente.
ImageBase
Imagem é como a Microsoft chama um arquivo executável (para diferenciar de um código-objeto) quando vai para a memória. Neste campo está o endereço de memória que é a base da imagem, ou seja, onde o programa será carregado em memória. Para arquivos executáveis (.EXE) o padrão é 0x400000. Já para bibliotecas (.DLL), o padrão é 0x10000000, embora executáveis do Windows como o calc.exe também apresentem este valor no ImageBase.
SubSystem
Este campo define o tipo de subsistema necessário para rodar o programa. Valores interessantes para nós são:
0x002 - Windows GUI (Graphical User Interface) - para programas gráficos no Windows (que usam janelas, etc).
0x003 - Windows CUI (Character User Interface) - para programas de linha de comando.
DllCharacteristics
Ao contrário do que possa parecer, este campo não é somente para DLL's. Ele está presente e é utilizado para arquivos executáveis também. Assim como o campo Characteristics do cabeçalho COFF visto anteriormente, este campo é uma máscara de bits com destaque para os possíveis valores:
6
IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
8
IMAGE_DLLCHARACTERISTICS_NX_COMPAT
O estado bit 6 nos diz se a randomização de endereços de memória, também conhecida por ASLR (Address Space Layout Randomization), está ativada para este binário, enquanto o estado do bit 8 diz respeito ao DEP (Data Execution Prevention), também conhecido pela sigla NX (No eXecute). O estudo aprofundado destes recursos foge do escopo inicial deste livro, mas é importante que saibamos que podemos desabilitar tais recursos simplesmente forçando estes bits para zero.
Diretórios de dados
Ainda como parte do cabeçalho opcional, temos os diretórios de dados, ou Data Directories. São 16 diretórios ao todo, cada um com uma função. Concentraremos, no entanto, nos mais importantes para este estudo inicial. A estrutura de cada diretório de dados é conhecida por IMAGE_DATA_DIRECTORY e tem a seguinte definição:
Vejamos agora alguns diretórios:
Export Table
O primeiro diretório de dados aponta para a tabela de exports, ou seja, de funções exportadas pela aplicação. Por isso mesmo sua presença (campos VirtualAddress e Size diferentes de zero) é muito comum em bibliotecas.
O campo VirtualAddress aponta para uma outra estrutura chamada EDT (Export Directory Table), que contém os nomes das funções exportadas e seus endereços, além de um ponteiro para uma outra estrutura, preenchida em memória, chamada de EAT (Export Address Table). Entenderemos mais sobre estas e outras estruturas em breve.
Import Table
Sendo a contraparte da Export Table, a Import Table aponta para a tabela de imports, ou seja, de funções importadas pela aplicação. O campo VirtualAddress aponta para a IDT (Import Directory Table), que tem um ponteiro para a IAT (Import Address Table), que estudaremos mais à frente.
Resource Table
Aponta para uma estrutura de árvore binária que armazena todos os resources num executável (ícones, janelas, strings - principalmente quando o programa suporta vários idiomas), etc. Também estudaremos um pouco mais sobre estes "recursos" no futuro.
Last updated