Ir para conteúdo

Formato PE - 4


Leandro Fróes

Posts Recomendados

Boa noite pessoal! Essas semanas andam meio corridas e não consegui estudar do jeito que gostaria, mas ainda sim bora lá, o importante é estudar, certo?

Peço que dêem uma olhada na estrutura do post passado (IMAGE_OPTIONAL_HEADER) e observem o último campo:

 

IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];

 

Para quem manja de C já bate o olho e de cara nota que isso é um array de estruturas chamado DataDirectory de tamanho IMAGE_NUMBEROF_DIRECTORY_ENTRIES e do tipo IMAGE_DATA_DIRECTORY

 

Se dermos uma olhada na biblioteca winnt.h podemos ver que há um valor pré-definido de 16 para o campo IMAGE_NUMBEROF_DIRECTORY_ENTRIES

 

#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16

 

A estrutura 'DataDirectory' segue o seguinte escopo:

 

typedef struct _IMAGE_DATA_DIRECTORY { 
	DWORD VirtualAddress;
	DWORD Size; 
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;

Esta estrutura possui, respectivamente, RVAs e Tamanhos de tabelas usadas em tempo de execução que podem ser usadas pelo Windows. Aqui está nossa referência:

 

Offset

(PE/PE32+)

Size

Field

Description

96/112

8

Export Table

The export table address and size. For more information see section 6.3, “The .edata Section (Image Only).”

104/120

8

Import Table

The import table address and size. For more information, see section 6.4, “The .idata Section.”

112/128

8

Resource Table

The resource table address and size. For more information, see section 6.9, “The .rsrc Section.”

120/136

8

Exception Table

The exception table address and size. For more information, see section 6.5, “The .pdata Section.”

128/144

8

Certificate Table

The attribute certificate table address and size. For more information, see section 5.7, “The Attribute Certificate Table (Image Only).”

136/152

8

Base Relocation Table

The base relocation table address and size. For more information, see section 6.6, "The .reloc Section (Image Only)."

144/160

8

Debug

The debug data starting address and size. For more information, see section 6.1, “The .debug Section.”

152/168

8

Architecture

Reserved, must be 0

160/176

8

Global Ptr

The RVA of the value to be stored in the global pointer register. The size member of this structure must be set to zero.

168/184

8

TLS Table

The thread local storage (TLS) table address and size. For more information, see section 6.7, “The .tls Section.”

176/192

8

Load Config Table

The load configuration table address and size. For more information, see section 6.8, “The Load Configuration Structure (Image Only).”

184/200

8

Bound Import

The bound import table address and size.

192/208

8

IAT

The import address table address and size. For more information, see section 6.4.4, “Import Address Table.”

200/216

8

Delay Import Descriptor

The delay import descriptor address and size. For more information, see section 5.8, “Delay-Load Import Tables (Image Only).”

208/224

8

CLR Runtime Header

The CLR runtime header address and size. For more information, see section 6.10, “The .cormeta Section (Object Only).”

216/232

8

Reserved, must be zero

 

1.png.fdb7e2f48b8ef4ac709272d960c68332.png

Aqui está nosso array, cada diretório representa um índice nesta lista. Vou pegar apenas um como exemplo, tendo em vista que todos os outros seguem o mesmo modelo:D

 

Este é o array na posição 1(considerando que estamos começando de zero). Este se chama Import Directory. Mais pra frente vou tentar falar melhor sobre ele, pois o danado é importante pra caramba.

2.png.132b01122e2427124f12f903bc250f69.png

3.png.aca68b6ee883023fbcb7b35a59a869dc.png

A primeira DWORD é o RVA da tabela (relativo ao BaseAddress) quando carregada em memória. A segunda DWORD é o tamanho dela em bytes.

 

Que tal revermos alguns conceitos?

 

Quando estamos olhando os bytes de um arquivo por meio de um editor/dumper hexa, estamos olhando diretamente para os bytes do arquivo em disco. Para quem está familiarizado com a seguinte instrução:

 

FILE *fp;

 

Saiba que isto significa um ponteiro para o primeiro byte do arquivo, isto é, o início em disco. Com um ponteiro para um arquivo podemos manipular(imprimir, alterar, pular) os bytes diretamente através de várias funções que estão a nossa disposição e isso tudo através de uma abstração chamada stream(abstração, interface, chame do que quiser). Nos nossos estudos estamos falando de um binário, não de um arquivo em formato texto!

 

Mais algumas considerações legais:

 

Por acaso o termo “Offset” significa algo pra vocês? Este significa deslocamento (em relação a algo). Lembram do RVA ? Relative Virtual Address? Ele tem a mesma ideia do offset e é relativo ao BaseAddress. Ainda não ficou claro? Vamos lá…

 

Quando executamos um programa é reservado um espaço de memória para ele chamado Virtual Address Space, o Windows cria este espaço para cada processo criado. O ‘VirtualAddress’(VA), também conhecido como Linear Address, pode ser achado facilmente. Lembram que o RVA é o deslocamento relativo ao BaseAddress? Sendo assim:

 

VA = BaseAddress + RVA

 

Vamos para a próxima estrutura!! Lembram do campo 'NumberOfSections' no FileHeader? O valor daquele campo nos mostra uma coisa interessante: o número de entradas na Section Table. Ok, não faz sentido *-*. Bom, no primeiro byte após os headers (logo após o ‘OptionalHeader’) está localizado um array de 'SectionHeaders' (ou Section Table Entries, use o que lhe agradar mais). Podemos referenciar da seguinte forma: struct IMAGE_SECTION_HEADER SectionHeaders[Num_no_Optional] e cada seção com seu respectivo índice no array.

 

A estrutura de cada SectionHeader segue o seguinte escopo:

 

typedef struct _IMAGE_SECTION_HEADER { 
	BYTE  Name[IMAGE_SIZEOF_SHORT_NAME]; 
	union { 
		DWORD PhysicalAddress; 
		DWORD VirtualSize; 
	} Misc; 
	DWORD VirtualAddress; 
	DWORD SizeOfRawData; 
	DWORD PointerToRawData; 
	DWORD PointerToRelocations;
	DWORD PointerToLinenumbers; 
	WORD  NumberOfRelocations; 
	WORD  NumberOfLinenumbers; 
	DWORD Characteristics; 
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;

No caso aqui não vou me preocupar em traduzir cada seção, tendo em vista que os campos do cabeçalho são iguais para todas. Vou apenas explicar pegando uma como exemplo e o resto deixo pra vocês :ph34r:

 

Name

 

O primeiro campo é um array de caracteres(uma string) com valor IMAGE_SIZEOF_SHORT_NAME, tá, mas o que é isso? Dê uma olhada neste campo do header winnt:

 

#define IMAGE_SIZEOF_SHORT_NAME 8

 

Lá está o valor. Tenha em mente que são 8 bytes contando com um caractere nulo no fim da string(este caractere nulo é ignorado caso o nome tenha de fato 8 bytes). Há alguns detalhes a mais nesta definição, mas vou me preocupar apenas com a imagem de um executável, esta que suporta até 8 bytes em UTF-8

4.png.db6fc20fe3998ce6329b74fa5646fe4c.png

Note que cada byte representa um caractere do nome(no caso aqui é .text) e o resto é preenchido com zeros, ou seja, é feito um padding, um preenchimento para chegarmos ao valor definido pela diretiva #define =D

 

Union (Misc)

 

Pra você que estudou um pouco de estrutura de dados, sabe o que é uma union? Resumindo é parecida com uma struct, a questão é que o espaço de memória usado para as variáveis da union é compartilhado (geralmente em momentos diferentes). O compilador cria automaticamente uma variável grande o bastante para conter o maior tipo de variável da union. Voltando ao PE:

 

PhysicalAddress e VirtualSize(Misc)

 

Aqui temos duas DWORDS, uma indicando o endereço no arquivo e outra indicando o tamanho da seção depois que for carregada em memória(em bytes). Se este valor for maior que ‘SizeOfRawData’ a seção é preenchida com zeros. O campo ‘VirtualSize’ só é válido para imagens executáveis e será zero para arquivos objeto.

5.png.4d7bb26d346957e0e0b12fa40ac4ed32.png

No nosso caso deu 5744 bytes, 0x1670h

 

VirtualAddress

 

Para imagens executáveis é uma DWORD indicando o RVA, o primeiro byte da seção quando carregada em memória(lembrando que temos que somar ao 'BaseAddress'). Para arquivos objeto os compiladores setam este valor para zero

6.png.83e7c3dff6c18e74cad60df103eebe1f.png

7.thumb.png.a10fba91913bdc23d3fc08c0ece43a42.png

Ali no canto esquerdo podemos ver o valor do VirtualAddress somado ao BaseAddress, resultando no primeiro byte da seção após ser carregada em memória =D

 

SizeOfRawData

 

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).

8.png.f2b592bde579218067f289968728afb1.png

No nosso exemplo, o valor encontrado é 0000 1800, faça a conta e veja se é múltiplo mesmo =D. Caso a seção possua apenas dados não-inicializados este campo é preenchido com zeros(como é o caso da seção .bss ;) )

 

PointerToRawData

 

Este campo é bem interessante(não que os outros não sejam, claro). Para executáveis é uma DWORD indicando o offset dentro do arquivo(e deve ser múltiplo de 'FileAlignment') até os dados da seção propriamente ditos. Caso a seção possua apenas dados não-inicializados este campo é preenchido com zeros, de novo…

9.png.fbc134172f7b9b59671f15bab66f0bd1.png

11.png.5184030d3e06a4fa706654fb35238cd7.png

No offset 400h na esquerda podemos ver justamente o início da seção .text em nosso arquivo ^_^

 

PointerToRelocations, PointerToLinenumbers, NumberOfRelocations e NumberOfLineNumbers

 

Aqui os dois primeiros campos são DWORDS e os seguintes WORDS. Todas estas informações somente são utilizadas para arquivos objeto, ou seja, estarão zeradas no nosso caso. 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.

12.png.bb639b29cb76df7bf88a68d8aa715438.png

 

Para deixar um pouco mais claro(bem por cima): COFF Relocations (que só acontece em arquivos objeto) é a forma como os dados da seção devem ser modificados quando colocados na imagem e, posteriormente, carregados em memória.

 

Characteristics

 

Uma DWORD com uma porção de flags dizendo características da seção. Podemos dizer que é uma enum. Segue a documentação:

 

 

Flag

Value

Description

 

0x00000000

Reserved for future use.

 

0x00000001

Reserved for future use.

 

0x00000002

Reserved for future use.

 

0x00000004

Reserved for future use.

IMAGE_SCN_TYPE_NO_PAD

0x00000008

The section should not be padded to the next boundary. This flag is obsolete and is replaced by IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files.

 

0x00000010

Reserved for future use.

IMAGE_SCN_CNT_CODE

0x00000020

The section contains executable code.

IMAGE_SCN_CNT_INITIALIZED_DATA

0x00000040

The section contains initialized data.

IMAGE_SCN_CNT_UNINITIALIZED_ DATA

0x00000080

The section contains uninitialized data.

IMAGE_SCN_LNK_OTHER

0x00000100

Reserved for future use.

IMAGE_SCN_LNK_INFO

0x00000200

The section contains comments or other information. The .drectve section has this type. This is valid for object files only.

 

0x00000400

Reserved for future use.

IMAGE_SCN_LNK_REMOVE

0x00000800

The section will not become part of the image. This is valid only for object files.

IMAGE_SCN_LNK_COMDAT

0x00001000

The section contains COMDAT data. For more information, see section 5.5.6, “COMDAT Sections (Object Only).” This is valid only for object files.

IMAGE_SCN_GPREL

0x00008000

The section contains data referenced through the global pointer (GP).

IMAGE_SCN_MEM_PURGEABLE

0x00020000

Reserved for future use.

IMAGE_SCN_MEM_16BIT

0x00020000

Reserved for future use.

IMAGE_SCN_MEM_LOCKED

0x00040000

Reserved for future use.

IMAGE_SCN_MEM_PRELOAD

0x00080000

Reserved for future use.

IMAGE_SCN_ALIGN_1BYTES

0x00100000

Align data on a 1-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_2BYTES

0x00200000

Align data on a 2-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_4BYTES

0x00300000

Align data on a 4-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_8BYTES

0x00400000

Align data on an 8-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_16BYTES

0x00500000

Align data on a 16-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_32BYTES

0x00600000

Align data on a 32-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_64BYTES

0x00700000

Align data on a 64-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_128BYTES

0x00800000

Align data on a 128-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_256BYTES

0x00900000

Align data on a 256-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_512BYTES

0x00A00000

Align data on a 512-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_1024BYTES

0x00B00000

Align data on a 1024-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_2048BYTES

0x00C00000

Align data on a 2048-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_4096BYTES

0x00D00000

Align data on a 4096-byte boundary. Valid only for object files.

IMAGE_SCN_ALIGN_8192BYTES

0x00E00000

Align data on an 8192-byte boundary. Valid only for object files.

IMAGE_SCN_LNK_NRELOC_OVFL

0x01000000

The section contains extended relocations.

IMAGE_SCN_MEM_DISCARDABLE

0x02000000

The section can be discarded as needed.

IMAGE_SCN_MEM_NOT_CACHED

0x04000000

The section cannot be cached.

IMAGE_SCN_MEM_NOT_PAGED

0x08000000

The section is not pageable.

IMAGE_SCN_MEM_SHARED

0x10000000

The section can be shared in memory.

IMAGE_SCN_MEM_EXECUTE

0x20000000

The section can be executed as code.

IMAGE_SCN_MEM_READ

0x40000000

The section can be read.

IMAGE_SCN_MEM_WRITE

0x80000000

The section can be written to.

 

Nesta parte não vou colocar o valor que deu no meu, vou apenas destacar um fato interessante que é: a seção .text possui permissão de leitura e execução (os bits 29 e 30 estão sempre setados nela), pelo menos deveriam 9_9

 

Muito obrigado por aguentar até aqui, espero que tenha sido claro e como sempre, qualquer feedback só mandar bala. Queria também avisar que coloquei todo esse material no meu github (https://github.com/leandropf/pecoff). Sei que não é lá essas coisas, apenas um mero mortal descrevendo os campos, mas ainda sim quem sabe não ajude alguém ou no mínimo dê uma direção :P.

 

Abraços e bom domingo!

Link para o comentário
Compartilhar em outros sites

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

  • Quem Está Navegando   0 membros estão online

    • Nenhum usuário registrado visualizando esta página.
×
×
  • Criar Novo...