Ir para conteúdo
Entre para seguir isso  
Leandro Fróes

Formato PE - 3

Posts Recomendados

Boa tarde pessoal!! Acharam que o PE ia abandonar vocês?? Que nada rapaz, só uma pausa do feriado msm pra galera dormir mais =D

Se me permitem, gostaria de fazer uma observação que se aplica nos estudos:

  • Estou colocando os campos da documentação aqui assumindo que sejam sempre verdadeiros, mas sabemos que não é bem assim. Este é o padrão que o Windows segue, mas quando o assunto é (in)segurança padrões são meio problemáticos(?!). Como o foco aqui é simplesmente apresentar o formato vou focar justamente nisso e deixar possíveis problemas/melhorias/macumbas para o futuro, depois que todos nós (e eu estou bem incluso nisso) entendermos tudo ;)

Bom, vamos ao que interessa?

Aqui faremos o uso de mais uma ferramenta, um debugger pra ser mais preciso. Usarei o OllyDbg na versão 2.01, mas fique à vontade para usar um de sua preferência.

 

E o que é um debugger? Resumindo é uma ferramenta com a capacidade de interpretação dos opcodes, transformando-os em linguagem assembly (disassembly) e permitindo interação com o binário compilado.

 

Lembram da estrutura IMAGE_NT_HEADERS?

typedef struct _IMAGE_NT_HEADERS {
  DWORD                                         Signature;
  IMAGE_FILE_HEADER             FileHeader;
  IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;

No post passado vimos o FileHeader, agora iremos para a IMAGE_OPTIONAL_HEADER que segue o seguinte formato segundo a documentação:

typedef struct _IMAGE_OPTIONAL_HEADER {
  WORD                   Magic;
  BYTE               	   MajorLinkerVersion;
  BYTE              	   MinorLinkerVersion;
  DWORD                SizeOfCode;
  DWORD                SizeOfInitializedData;
  DWORD                SizeOfUninitializedData;
  DWORD                AddressOfEntryPoint;
  DWORD                BaseOfCode;
  DWORD                BaseOfData;
  DWORD                ImageBase;
  DWORD                SectionAlignment;
  DWORD                FileAlignment;
  WORD                   MajorOperatingSystemVersion;
  WORD                   MinorOperatingSystemVersion;
  WORD                   MajorImageVersion;
  WORD                   MinorImageVersion;
  WORD                   MajorSubsystemVersion;
  WORD                   MinorSubsystemVersion;
  DWORD                Win32VersionValue;
  DWORD                SizeOfImage;
  DWORD                SizeOfHeaders;
  DWORD                CheckSum;
  WORD                   Subsystem;
  WORD                   DllCharacteristics;
  DWORD                SizeOfStackReserve;
  DWORD                SizeOfStackCommit;
  DWORD                SizeOfHeapReserve;
  DWORD                SizeOfHeapCommit;
  DWORD                LoaderFlags;
  DWORD                NumberOfRvaAndSizes;
  IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;

Grandinho, né? Bem, aqui temos o nome “opcional”, mas na verdade toda imagem possui um cabeçalho deste (entenda imagem como um programa carregado em memória). Este header possui informações importantes que ajudam no carregamento e execução do nosso executável.

 

Magic

 

A identificação do tipo de imagem é feito deste campo. Aqui podemos ver se ela é um PE32, PE32+ ou uma ROM image. Os bytes no caso seriam:

 

0x10B - PE32

0x107 – ROM Image

0x20B – PE32+

image.png.5d686ddf9a56ac7c3ae50b70f423d983.png

PE32, certo? O zero da esquerda é omitido ali em cima, mas ainda sim são dois bytes.

 

MajorLinkerVersion e MinorLinkerVersion

 

Simplesmente um byte indicando a maior versão do linker e outro byte indicando a menor. Sempre que leio algo sobre PE dizem que este campo não é lá essas coisas, eu não faço ideia da versão do meu linker, por exemplo, então se alguém souber uma utilidade interessante para este campo pf me ajude :o

image.png.4295aca47906a80d0d6bce33806231b6.png

Converta ai pra decimal rapaz!!!

 

SizeOfCode

 

DWORD indicando o tamanho, em bytes, da seção .text (ou .code) ou a soma de todas essas seções se houver várias seções de texto

image.png.bdad80414444751af720d30afacc3da5.png

Entenda que quando falamos que a seção se chama .text é simplesmente um nome, uma convenção para o loader as identificar.

 

SizeOfInitializedData

 

DWORD indicando o tamanho, em bytes, da seção .data ou a soma de todas essas seções se houver várias seções de dados inicializados.

image.png.e5793406de5bda76821d025f0e631782.png

 

SizeOfUninitializedData

 

DWORD indicando o tamanho, em bytes, da seção .bss ou a soma de todas essas seções se houver várias seções de dados não inicializadas.

image.png.6f1f324f209484029f7050987a67f0a1.png

 

AddressOfEntryPoint

 

Aqui temos uma DWORD que é o endereço do Entry Point (um RVA para ser mais exato) relativo ao Base Address que indica (pelo menos deveria) o começo do programa em memória. Para executáveis este é o começo do programa, para drivers é a função de inicialização e para DLL's é um campo opcional. Caso não haja E.P o campo será zero.

image.png.0ca9ec46c42e10e791603bb34ad91350.png

image.png.58d908e44b0f7aca232edb78ff9ccbaf.png

Olha lá o danado no Debugger :ph34r:. Note que há um número somado ao nosso RVA, este se chama BaseAddress, veremos mais pra frente.

 

BaseOfCode

 

DWORD relativa ao Base Address indicando o endereço do começo da seção .text(.code) quando ela é carregada em memória, seu RVA.

image.png.573b510d880d0ce41e553a6697edc73a.png

 

BaseOfData

 

DWORD relativa ao Base Address indicando o endereço do começo da seção .data quando ela é carregada em memória, RVA novamente.

image.png.8e50898eef7e5832c36fd2cec969d5e9.png

 

ImageBase

 

Quando temos uma imagem carregada em memória precisamos de um endereço para ela, certo? Um executável possui um endereço preferencial, assim como uma DLL. Este endereço é uma DWORD e é chamado de BaseAddress, pois indica o primeiro byte em memória. O valor preferencial para aplicações Windows NT, XP, 95, 98, 2000 é 0x00400000 (explicado o porque dos valores do Olly, né?=D) e para DLL's 0x00010000.

image.png.bd385280dc7a3e3a6e7643ee51d8479a.png

0x400000 o nosso, faz algum sentido o valor ali no debugger agora ? Some ai: 0x400000 + 0x14E0 :P

 

SectionAlignment

 

Alinhamento da seção (em bytes) quando é carregada em memória indicado por uma DWORD. O tamanho padrão é de uma página de acordo com a arquitetura.

image.png.e902f172c25021d7e78ea210958c38ea.png

Nosso alinhamento de seção é de 4096 bytes.

 

FileAlignment

 

Alinhamento dos dados propriamente ditos das seções da imagem. O padrão é 512. Caso o SectionAlignment seja menor que o tamanho de uma página o FileAlignment será o mesmo do SectionAlignment.

image.png.965934be01492987637ac4612f914e08.png

200h = 512 dec, então estamos com o padrão mesmo.

 

MajorOperatingSystemVersion e MinorOperatingSystemVersion

 

2 WORDS indicando a maior e menor versão do sistema requerido. Não sei muito bem sobre este campo =/

image.png.1283cdfebae84de35acf66972a7e79a5.png

image.png.bc493fd6228a90225fc1e55e34c4d562.png

 

MajorImageVersion e MinorImageVersion

 

2 WORDS indicando a maior e menor versão da imagem. Também não sei muito sobre

image.png.cf94f1a9f0541e9d24b8b229815e1d10.png

image.png.12ed5031c301e07d3e4aceb5fdf52b0b.png

 

MajorSubsystemVersion e MinorSubsystemVersion

 

2 WORDS indicando a maior e menor versão do SubSystem. Este campo deve ser checado pois a versão vai influenciar na maneira como a aplicação rodará (questão gráfica, por exemplo)

image.png.6ed4029f893b4273aa322e1158f14c62.png

image.png.03d665894a0a512f98ec36973145a364.png

 

Win32VersionValue

 

DWORD reservada e é sempre zero aparentemente.

image.png.a604be512503e5d952925c85be05da53.png

 

SizeOfImage

 

DWORD que indica o tamanho total (em bytes) da imagem quando carregada em memória, aqui estão inclusos os headers, seções etc e este tamanho deve ser múltiplo da SectionAlignment(até porque este alinhamento trata da imagem carregada).

image.png.e5f50625f4c836104e5acf968f6140e8.png

Vamos ver se é múltiplo ? Lembrando que nosso resto deve ser zero. Vamos rodar a ferramenta mais potente do nosso arsenal, a calculadora do windows *-* (brincadeira, usem o shell mesmo). 0x01D000 = 118784 em decimal, dividimos entao por 4096 (alinhamento da seção) e obtemos 29 com resto zero, certinho!!

 

SizeOfHeaders

 

A soma de todos os cabeçalhos, data directory e cabeçalhos das seções. Esta DWORD deve ser múltipla do FileAlignment e é o offset do começo do arquivo até os dados propriamente ditos.

image.png.069b98f7909add595fcb0d7bafcabde9.png

Saque sua calculadora e faça novamente a conta, mas agora convertendo e dividindo por 512, aqui deu 1024 e na divisão deu 2, confere?

 

 

CheckSum

 

Esta DWORD , para as versões atuais do NT, só é checada 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. No nosso caso tem essa macumba ai (o algoritmo para calcular o checksum não é explicitamente aberto).

image.png.c5548e31ff8789bef5db1daaa3cc4e9f.png

 

Subsystem

 

Esta WORD representa o Subsystem esperado para executar a imagem. Segue a tabelinha da doc:

 

 

Constant

Value

Description

IMAGE_SUBSYSTEM_UNKNOWN

0

An unknown subsystem

IMAGE_SUBSYSTEM_NATIVE

1

Device drivers and native Windows processes

IMAGE_SUBSYSTEM_WINDOWS_GUI

2

The Windows graphical user interface (GUI) subsystem

IMAGE_SUBSYSTEM_WINDOWS_CUI

3

The Windows character subsystem

IMAGE_SUBSYSTEM_OS2_CUI

5

The OS/2 character subsystem

IMAGE_SUBSYSTEM_POSIX_CUI

7

The Posix character subsystem

IMAGE_SUBSYSTEM_NATIVE_WINDOWS

8

Native Win9x driver

IMAGE_SUBSYSTEM_WINDOWS_CE_GUI

9

Windows CE

IMAGE_SUBSYSTEM_EFI_APPLICATION

10

An Extensible Firmware Interface (EFI) application

IMAGE_SUBSYSTEM_EFI_BOOT_ SERVICE_DRIVER

11

An EFI driver with boot services

IMAGE_SUBSYSTEM_EFI_RUNTIME_ DRIVER

12

An EFI driver with run-time services

IMAGE_SUBSYSTEM_EFI_ROM

13

An EFI ROM image

IMAGE_SUBSYSTEM_XBOX

14

XBOX

IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION

16

Windows boot application.

 

Para você que curte programar em C essa tabela é uma *enum* =D. E qual o nosso valor?

image.png.c70d0f0ae173dd4fdf7dd17ef5decf5d.png

 

DllCharacteristics

 

Características da imagem da DLL (isso se for uma, claro). No nosso caso não é então o campo de 16 bits (WORD) estará zerado.

image.png.aa637830a18f44c43d91ecaa27dae361.png

 

SizeOfStackReserve e SizeOfStackCommit

 

Aqui temos 2 DWORDS indicando o espaço que será reservado para a Stack e o espaço que de fato será entregue no momento que carregar a imagem, respectivamente. Se você não sabe muito bem o que é a estrutura de uma pilha aconselho dar uma lidinha rápida =)

image.png.8530e297fb1a3fc0d374b48f06748a6d.png

image.png.9bc673ed7d70d991579039026d3a6d73.png

Aqui no caso será entregue COMMITED bytes e caso precise de mais espaço iremos de crescer uma página de cada vez (consulte o tamanho da página de acordo com a arquitetura) até chegar no valor reservado que é: RESERVED

 

SizeOfHeapReserve e SizeOfHeapCommit

 

Mais duas DWORDS seguidas com a mesma ideia dos campos explicados acima =)

image.png.d622e5b417045edd8899eaeaf81b14b9.png

image.png.58d0a5e6f7fff4cc941c1b209a2121b0.png

 

LoaderFlags

 

DWORD aparentemente reservada e com o valor zerado

image.png.a686f9b326df170f9416f46fee070cd2.png

 

NumberOfRvaAndSizes

 

DWORD indicando o número de entradas do DataDirectory (último item da nossa estrutura e que veremos posteriormente). Cada entrada mostra uma localização e um tamanho, respectivamente.

image.png.31a9da76b05ac5a89fa7be645ff98a70.png

 

Que tal conferirmos tudo isso com o grande readpe do pev?

image.png.9c979076ea15a97798ba733e8ae1d393.png

Aparentemente tudo certo...Chegamos ao fim de mais uma estrutura!! Ficou com alguma dúvida? Pretendo pontuar alguns conceitos interessantes para melhor entendimento do PE mais pra frente, mas não deixem de estudar. Conto com vocês para melhorarem as besteiras que eu falo hein 9_9.

 

Feedbacks etc etc só mandar bala e obrigado!! xD

 

 

Editado por Leandro Fróes
  • Like 1

Compartilhar este post


Link para o post
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisar ser um membro para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar Agora

Entre para seguir isso  

×