Informática Numaboa - Referências
O formato PE
Sab 11 Abr 2009 11:01 |
- Detalhes
- Categoria: Formatos padrão
- Atualização: Sábado, 11 Abril 2009 23:44
- Autor: vovó Vicki
- Acessos: 14446
Cabeçalho opcional
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 |
Imediatamente após o cabeçalho do arquivo vem o cabeçalho opcional que, apesar do nome, está sempre presente. Este cabeçalho contém informações de como o arquivo PE deve ser tratado. Os componentes do cabeçalho opcional são os seguintes:
- Magic
- MajorLinkerVersion e MinorLinkerVersion
- Tamanho do Código, Segmento de Dados e Segmento BSS
- AddressOfEntryPoint - O Ponto de Entrada do Código do Executável
- Base do Código e Base dos Dados
- Base da Imagem
- Alinhamento
- Versão do Sistema Operacional
- Versão do Binário
- Versão do Subsistema
- Versão do Win32
- Tamanho da Imagem
- Tamanho dos Cabeçalhos
- CheckSum
- Subsistema NT
- Características de DLL
- Tamanho da Reserva de Pilha (StackReserve)
- Loader Flags
- Número e Tamanho dos RVA
Magic
O primeiro word de 16 bits do cabeçalho opcional é o 'Magic'. Em todos os arquivos PE que analisei até hoje, o valor encontrado sempre foi 010B.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 |
MajorLinkerVersion e MinorLinkerVersion
O próximo componente do cabeçalho opcional, composto de 2 bytes, reflete as versões Maior e Menor do linker utilizado. Estes valores, novamente, não são confiáveis e nem sempre refletem apropriadamente a versão do linker. Muitos linkers nem mesmo utilizam estes campos. Aliás, se não se tem a mínima idéia de qual linker tenha sido utilizado, qual é a vantagem de conhecer a versão?
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C |
Tamanho do Código, Segmento de Dados e Segmento BSS
Os 3 valores de 32 bits seguintes referem-se ao Tamanho do Código Executável ('SizeOfCode'), ao Tamanho dos Dados Inicializados ('SizeOfInitializedCode') e ao Tamanho dos Dados não Inicializados ('SizeOfUninitializedCode'). O tamanho dos dados inicializados também é conhecido como Segmento de Dados (Data Segment) e o tamanho dos dados não inicializados é conhecido como Segmento BSS (BSS Segment). Estes dados, uma vez mais, não são confiáveis! Por exemplo: o segmento de dados pode estar dividido em vários segmentos por ação do compilador ou do linker. O melhor que se tem a fazer é inspecionar as seções para ter uma idéia mais aproximada dos tamanhos.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 |
Ponto de entrada do código executável
O próximo valor de 32 bits é um RVA. Se você tiver dúvidas sobre RVAs, NÃO CONTINUE. Volte para a página anterior e leia com atenção as Considerações sobre RVAs. A partir deste ponto, se você não estiver familiarizado com as ditas cujas... vai perder o passo!
Este RVA é o offset para o Ponto de Entrada do Código ('AddressOfEntryPoint'), ou seja, é onde a execução do nosso binário, MAPEADO NA MEMÓRIA, realmente começa.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 |
Invertendo os bytes, obtemos o RVA do Endereço do Ponto de Entrada: 00 10 00 00 -> 00 00 10 00. Este valor (1000) é o que será adicionado ao endereço base quando nosso programa for mapeado na MEMÓRIA. Imagine que, ao ser executado, o executável tenha sido mapeado na memória a partir do endereço 40000. Qual será o ponto de entrada do código? Simples: 40000 + 1000 = 41000. Entendeu agora porque o valor deste campo é um RVA?
Base do Código e Base dos Dados
Logo após o importantíssimo Ponto de Entrada encontram-se dois valores de 32 bits, o 'BaseOfCode' (base do código) e o 'BaseOfData' (base dos dados), ambos também RVAs. Infelizmente os dois também perdem importância (como tantos outros campos) por que a informação obtida através da análise das seções é muito mais confiável.
Não existe uma base de dados não inicializados porque, por não serem inicializados, não há necessidade de incluir esta informação na imagem.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 |
Base da Imagem
Segue uma entrada de um valor de 32 bits que indica o endereço de mapeamento preferencial, chamado de endereço linear e correspondendo à 'BaseImage'. No momento da execução, se este endereço de memória estiver vago, o binário inteiro (incluindo os cabeçalhos) será transferido para lá. Este é o endereço, sempre um múltiplo de 64, para onde o binário é remanejado pelo linker. Se o endereço estiver disponível, o carregador (loader) não precisará remanejar o arquivo, o que representa um ganho no tempo de carregamento.
O endereço preferido de mapeamento não pode ser utilizado se outra imagem já tiver sido mapeada para este endereço (uma colisão de endereços, a qual ocorre com alguma frequência quando se carrega várias DLLs que são remanejadas para o default do linker) ou se a memória em questão estiver sendo usada para outros fins (stack, malloc(), dados não inicializados, etc). Nestes casos, a imagem precisa ser transferida para algum outro endereço (veja 'diretório de remanejamento' logo a seguir). Este fato gera consequências posteriores se a imagem pertencer a uma DLL por que, neste caso, as importações casadas ("bound imports") deixam de ser válidas e há a necessidade de efetuar correções nos binários que utilizam estas DLLs - veja também em 'diretório de remanejamento' a seguir.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 |
Alinhamento
Os dois valores de 32 bits seguintes são os alinhamentos das seções do arquivo PE na RAM ('SectionAlignment', quando a imagem estiver carregada na memória) e no arquivo em disco ('FileAlignment'). Geralmente ambos valores são 32, ou então FileAlignment (alinhamento de arquivo) é 512 e SectionAlignment (alinhamento de seções) é 4096. As seções serão vistas posteriormente.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
No nosso exemplo, o alinhamento de seções é 4096 (0010 0000 -> inverso 0000 1000 -> 4096 decimal) e o alinhamento de arquivo é 512 (0002 0000 -> inverso 0000 0200 -> 512 decimal).
Versão do Sistema Operacional
Os dois valores seguintes são de 16 bits e referem-se à versão esperada do sistema operacional ('MajorOperatingSystemVersion' e 'MinorOperatingSystemVersion'). Esta informação da versão é apenas para o sistema operaconal, por exemplo NT ou Win98, ao contrário da versão do sub-sistema, por exemplo Win32. Geralmente esta informação não é fornecida ou está errada. Aparentemente o carregador (loader) não faz uso da mesma, portanto...
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 |
Versão do Binário
Os dois valores de 16 bits seguintes fornecem a versão do binário ('MajorImageVersion' e 'MinorImageVersion'). Muitos linkers não fornecem dados corretos e uma grande parte dos programadores nem se dá ao trabalho de fornecê-los. O melhor é se fiar na versão dos recursos (resource), contanto que exista.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
Versão do Sub-sistema
Os próximos 2 words de 16 bits são para a versão do sub-sistema esperado ('MajorSubsystemVersion' e 'MinorSubsystemVersion'). Esta versão deveria ser Win32 ou POSIX, por que os programas de 16 bits ou os do OS/2 obviamente não estão em formato PE.
Esta versão de subsistema deve ser fornecida corretamente porque ela É checada e usada:
- Se o aplicativo for um do tipo Win32-GUI, tiver que rodar em NT4 e a versão do sub-sistema não for 4.0, as caixas de diálogo não terão o estilo 3D e alguns outros aspectos terão a aparência do "estilo antigo". Isto porque o aplicativo acaba sendo rodado no NT 3.51, o qual possui o program manager ao invés do explorer, etc, e o NT 4.0 tentará imitar o 3.51 da melhor maneira possível.
- Idem para Win98 e WinMe. O aplicativo indica Win98 e o sistema da máquina é WinMe, então o WinMe tenta de tudo para imitar o Win98...
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
Versão do Win32
Só Deus sabe para é que serve este próximo valor de 32 bits. Está sempre zerado (veja acima).
Tamanho da Imagem
Este valor de 32 bits indica a quantidade de memória necessária para abrigar a imagem, em bytes ('SizeOfImage'). É a soma do comprimento de todos os cabeçalhos e seções, se estiverem alinhados de acordo com o 'SectionAlignement'. Indica para o carregador quantas páginas serão necessárias para carregar completamente a imagem.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
0000 0110 | 00 | 50 | 00 | 00 |
No nosso exemplo, obedecendo o alinhamento de seções de 4096 (veja acima), são requeridos 20.480 bytes para abrigar a imagem do executável na memória. Basta calcular: 0050 0000 -> inverso 0000 5000 -> 20.480 decimal.
Tamanho dos Cabeçalhos
O próximo valor de 32 bits é o tamanho de todos os cabeçalhos, incluindo os diretórios de dados e os cabeçalhos das seções ('SizeOfHeaders'). Representa o offset do início do arquivo até os dados (raw data) da primeira seção.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
0000 0110 | 00 | 50 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 |
No nosso exemplo, o offset do início do arquivo até os dados propriamente ditos é de 0000 0400 que, em decimal, corresponde a 1024 bytes.
CheckSum
Segue-se o valor de 32 bits do 'CheckSum'. O valor do checksum, para as versões atuais do NT, só é checado se a imagem for um driver NT (o driver não carregará se o checksum não estiver correto). Para outros tipos de binários o checksum não precisa ser fornecido e pode ser 0.
O algoritmo para calcular o checksum é propriedade da Microsoft e o pessoal da MS não entrega o ouro. No entanto, diversas ferramentas do Win32 SDK calculam e/ou inserem um checksum válido. Além disto, a função CheckSumMappedFile(), que faz parte da imagehelp.dll, também faz o serviço completo.
A função do checksum é a de evitar que binários "bichados", que vão dar pau de qualquer forma, sejam carregados - e um driver com pau acaba em BSOD, portanto, é melhor nem carregar.
No nosso exemplo, que não é para NT, o valor está zerado (veja acima).
Subsistema NT
O próximo valor de 16 bits, o 'Subsystem', indica em qual subsistema do NT a imagem deve rodar:
Nome | Valor | Significado |
IMAGE_SUBSYSTEM_NATIVE | 1 | O binário não precisa de um subsistema. É usado para drivers. |
IMAGE_SUBSYSTEM_WINDOWS_GUI | 2 | A imagem é um binário Win32 gráfico. Ainda pode abrir um console com AllocConsole(), porém não abre automaticamente no startup. |
IMAGE_SUBSYSTEM_WINDOWS_CUI | 3 | O binário é um Win32 de console. Receberá um console no startup (default) ou herda um console (parent's console). |
IMAGE_SUBSYSTEM_OS2_CUI | 5 | O binário é um OS/2 de console. Os binários OS/2 estarão em formato OS/2, portanto, este valor raramente será encontrado num arquivo PE. |
IMAGE_SUBSYSTEM_POSIX_CUI | 7 | O binário usa um subsistema de console POSIX. |
Binários do Windows 9x sempre usarão o subsistema Win32, portanto, os únicos valores aceitáveis para estes binários são 2 e 3. Desconheço se binários "nativos" do windows 9x são aceitos.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
0000 0110 | 00 | 50 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 02 | 00 | 00 | 00 |
Características de DLL
Este próximo valor de 16 bits indica quando o ponto de entrada deve ser chamado, SE a imagem for de uma DLL. No nosso exemplo, este valor está logicamente zerado (veja acima). Este é mais um campo que parece não ter uso: aparentemente, as DLL recebem notificações de tudo e prescindem deste campo. Novamente os bits são usados para guardar informações:
Bit | Setado (valor 1) |
0 | Notifica uma anexação de processo (isto é, DLL load) |
1 | Notifica um desligamento de thread (isto é, termina um thread ativo) |
2 | Notifica uma anexação de thread (isto é, cria um thread novo) |
3 | Notifica um desligamento de processo (isto é, DLL unload) |
Tamanho da Reserva de Pilha (StackReserve)
Os próximos 4 valores de 32 bits são o tamanho da reserva de pilha ('SizeOfStackReserve'), o tamanho do commit inicial da pilha ('SizeOfStackCommit'), o tamanho da reserva de heap ('SizeOfHeapReserve') e o tamanho do commit do heap ('SizeOfHeapCommit').
As quantidades 'reservadas' são espaços endereçados (não RAM real) que são reservados para um propósito específico. No início do programa, a quantidade "committada" é alocada na RAM. O valor "committado" é também o quanto a pilha ou o heap "committados" irão crescer caso for necessário. Alguns autores alegam que a pilha cresce em páginas, independentemente do valor do 'SizeOfStackCommit'.
Vamos a um exemplo: se o programa possui uma reserva de heap de 1 MB e um commit de heap de 64 Kb, o heap começa com 64 Kb e pode ser expandido até 1 MB. O heap irá crescer de 64 em 64 Kb. O 'heap' neste contexto é o heap primário (default). Um processo pode criar mais heaps se houver necessidade.
Como as DLLs não possuem pilha ou heap próprios, estes valores são ignorados nas suas imagens.
Offset | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
0000 00C0 | 50 | 45 | 00 | 00 | 4C | 01 | 03 | 00 | A3 | 77 | 55 | 3C | 00 | 00 | 00 | 00 |
0000 00D0 | 00 | 00 | 00 | 00 | E0 | 00 | 0F | 01 | 0B | 01 | 05 | 0C | 00 | 02 | 00 | 00 |
0000 00E0 | 00 | 0E | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 10 | 00 | 00 |
0000 00F0 | 00 | 20 | 00 | 00 | 00 | 40 | 00 | 00 | 00 | 10 | 00 | 00 | 00 | 02 | 00 | 00 |
0000 0100 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
0000 0110 | 00 | 50 | 00 | 00 | 00 | 04 | 00 | 00 | 00 | 00 | 00 | 00 | 02 | 00 | 00 | 00 |
0000 0120 | 00 | 00 | 10 | 00 | 00 | 10 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 10 | 00 | 00 |
0000 0130 | 00 | 00 | 00 | 00 | 10 | 00 | 00 | 00 |
Loader Flags
Os próximos 32 bits são das 'LoaderFlags' (flags do carregador) para as quais não há uma descrição adequada. No nosso exemplo, de qualquer maneira, todas as flags estão zeradas (veja acima).
Número e Tamanho dos RVA
O número e tamanho dos RVAs ('NumberOfRvaAndSizes') se encontram nos 32 bits seguintes e revelam o número de entradas válidas nos diretórios que vêm logo a seguir. Este número parece não ser muito confiável. No nosso exemplo, veja também acima, são 16 (1000 0000 -> invertendo 0000 0010 -> 16 decimal).
:anota: Exercícios propostos
Para este módulo, tente o seguinte:
- Procure por executáveis de todos os tamanhos. Qualquer um serve, contanto que esteja no formato PE. Localize o cabeçalho opcional dos binários e encontre o ponto de entrada, o importantíssimo ENTRY POINT.
- Faça alguns exercícios com diversos endereços base de memória e aplique o RVA do ponto de entrada (como explicado no item "Ponto de Entrada do Código do Executável").