• STATISTIQUES
  • Il y a eu un total de 1 membres et 13597 visiteurs sur le site dans les dernières 24h pour un total de 13 598 personnes!


    Membres: 2 433
    Discussions: 3 585
    Messages: 32 831
    Tutoriels: 78
    Téléchargements: 38
    Sites dans l'annuaire: 58


  • ANNUAIRE
  • [EN] Net Force
    Javascript: 9, Java Applets: 6, Cryptography: 16, Exploits: 7, Cracking: 14, Programming: 13, Internet: 15, Steganograph...
    Challenges
    [EN] Hack this site
    Basic: 11, Realistic: 17, Application: 18, Programming: 12, Extbasic: 14, Javascript: 7, Stego: 17
    Challenges
    [FR] frameip
    le site de partage des connaissances du monde TCPIP
    Protocole
    [EN] This is legal
    Basic: 10, Realistic: 5, Programming: 1, Bonus: 11, SQL: 2, Encryption: 6, Application: 4, User Contributed: 3
    Challenges
    [FR] PHP Débutant
    Apprendre le PHP par l'exemple, facilement et simplement. Réservé d'abord aux débutants....
    Programmation
    [FR] dcode
    dcode.fr est le site indispensable pour décoder des messages, tricher aux jeux de lettres, résoudre des énigmes...
    Outils / Add-on
    [FR] NewbieContest
    Nous vous proposons une série de challenges regroupant plusieurs domaines allant de l'exploitation de fail...
    Hacking

  • DONATION
  • Si vous avez trouvé ce site internet utile, nous vous invitons à nous faire un don du montant de votre choix via Paypal. Ce don servira à financer notre hébergement.

    MERCI!




Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Le PE Header - Pour commencer
05-05-2012, 19h48 (Modification du message : 08-12-2012, 17h36 par ark.)
Message : #1
supersnail Hors ligne
Éleveur d'ornithorynques
*******



Messages : 1,613
Sujets : 72
Points: 466
Inscription : Jan 2012
Le PE Header - Pour commencer
Introduction

Le format PE, est un format de fichier propre aux binaires Windows (c'est-à-dire exécutables, DLL, drivers) permettant à notre cher Windows de charger et lancer ces derniers. Ces structures contiennent des informations plus ou moins utiles, comme la table des sections, l'adresse du point d'entrée de l'exécutable ou encore l'adresse du dealer de chocapicz le plus proche de chez vous.

Pour bien profiter de cette visite guidée, il est recommandé d'avoir des notions en C (utilisation massive de pointeurs/structures au programme), et être un minimum à l'aise avec la notation hexadécimale. Il est aussi recommandé d'avoir un éditeur hexadécimal et une calculatrice (celle de Windows fera l'affaire) pour réaliser quelques bidouillages.


Préparatifs: les offsets, RVA et autres (D)WORDs

Il va nous falloir ici différentier deux mondes totalement différents: le monde des fichiers, et celui de la mémoire vive.Un exécutable est un fichier de ce qu'il y a de plus banal (au même titre qu'un fichier texte ou une image jpg), mais qui a pour but ultime d'être chargé en mémoire par le système d'exploitation (en l'occurence Windows, ou ReactOS si vous êtes un libriste convaincu aimant le goût du risque Wink ). Cet exécutable chargé en mémoire subira différentes transformations, le rendant ainsi complètement différent du fichier dont il est issu (modifiant les adresses mémoires par le fait).

C'est pour ça que les ingénieurs de Microsoft ont introduit un système intelligent de découpage en sections et de RVA (Relative Virtual Address) qui sert de base à la plupart des adresses qu'on rencontrera, plûtot que de baser les adresses sur les offsets du fichier.
Un offset est en quelque sorte la position d'un élement dans le fichier. Par exemple, si je veux lire le caractère à l'offset 4, je lirai le 5 caractère du fichier (étant donné que la numérotation des offset commence à partir de 0 au lieu de 1). A noter ici qu'on préfèrera utiliser une notation hexadécimale pour les offsets (ainsi que pour les adresses mémoire et les RVAs) par convention, même s'il est possible d'utiliser une notation décimale (ainsi le caractère à l'offset 10 ou 0x0A est le 11ème caractère du fichier, car 0x0A en hexadécimal correspond à 10 en décimal).

Les RVA, elles sont plus subtiles, puisqu'elles dépendent d'une entité appelée "table de sections" pour exister. En effet, un exécutable range son code dans des "sections" qui seront chargées en mémoire selon les informations contenues dans la table des sections (sur laquelle je reviendrai plus en détail sur la 2ème partie du tuto). La RVA représente l'adresse en mémoire d'une entité, relativement à l'adresse de base, c'est-à-dire par rapport à l'adresse où est chargée l'exécutable par le système d'exploitation (souvent 0x00400000).

Enfin, on trouvera souvent des noms du type "WORD", "DWORD" ou "BYTE" utilisés dans nos structures.
Il s'agit juste de variables ayant une certaine longueur d'octets. Un DWORD pour Double Word est une variable qui prend 4 octets consécutifs en mémoire (en little-endian, c'est-à-dire que les octets successifs dans la RAM 0x01 0x02 0x03 0x04 donneront 0x04030201 représentés par le DWORD). Le WORD lui, est une variable qui prend 2 octets consécutifs en mémoire (toujours en little-endian), et le BYTE, un seul octet.

Début de la randonnée: le MZ Header

Ouvrons notre exécutable avec notre éditeur hexadécimal, et admirons la jolie bouille d'octets servie pour notre déjeuner ! Vous reconnaissez sûrement le célèbre "This program can't run in DOS mode" si vous vous êtes déjà amusés à ouvrir un exécutable dans le bloc-notes lorsque vous étiez petits. Les premiers octets correspondent ici au MZ Header, ou encore l'en-tête MS-DOS (et oui, un exécutable Windows n'est rien d'autre qu'un exécutable MS-DOS avec des fonctionnalités supplémentaires).
Voici donc la structure représentant le MZ header:

Code C :
typedef struct _IMAGE_DOS_HEADER {
WORD e_magic; /* 00: MZ Header signature */
WORD e_cblp; /* 02: Bytes on last page of file */
WORD e_cp; /* 04: Pages in file */
WORD e_crlc; /* 06: Relocations */
WORD e_cparhdr; /* 08: Size of header in paragraphs */
WORD e_minalloc; /* 0a: Minimum extra paragraphs needed */
WORD e_maxalloc; /* 0c: Maximum extra paragraphs needed */
WORD e_ss; /* 0e: Initial (relative) SS value */
WORD e_sp; /* 10: Initial SP value */
WORD e_csum; /* 12: Checksum */
WORD e_ip; /* 14: Initial IP value */
WORD e_cs; /* 16: Initial (relative) CS value */
WORD e_lfarlc; /* 18: File address of relocation table */
WORD e_ovno; /* 1a: Overlay number */
WORD e_res[4]; /* 1c: Reserved words */
WORD e_oemid; /* 24: OEM identifier (for e_oeminfo) */
WORD e_oeminfo; /* 26: OEM information; e_oemid specific */
WORD e_res2[10]; /* 28: Reserved words */
DWORD e_lfanew; /* 3c: Offset to extended header */
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;


La plupart de ces champs étaient utiles lors d'une époque aujourd'hui révolue, mais subsiste encore un champ que Windows va lire: le champ e_lfanew (à l'offset 0x3c), qui contient l'offset du PE header à proprement parler.
Là, certaines tapz qui n'ont pas suivi se sentiront perdues, ne sachant pas ce qu'est l'offset d'un fichier. L'offset X (où X est un nombre), correspond tout simplement au Xème octet du fichier. Autrement dit, le DWORD commençant au 0x3c-ème octet (c'est-à-dire au 60ème octet du fichier) nous donne où on peut trouver le PE header dans le fichier (rappelez-vous, on est en little-endian, il faut donc lire les octets 60 à 64 à l'envers).
Après ce champ e_lfanew vient du code prévu pour MS-DOS (généralement un message affichant "This program can't run in DOS mode" dont les plus vieux se souviennent sûrement encore). Bref, passons ce moment d'extrême émotion, et continuons notre visite.

Le PE Header

Allons donc à l'offset indiqué par le vieux sage des montagnes pour y trouver notre PE Header. Les 4 premiers octets du PE header forment les lettres "PE", le tout suivi de deux octets nuls. Cette suite de caractères ne sert à rien, à part permettre à Windows de vérifier qu'il est bien face à un binaire bien formé (et non face un chocapicz mutant qui se serait perdu à cet endroit).
Le PE Header est séparé (dixit winnt.h) en 2 structures de taille inégale: le IMAGE_FILE_HEADER qui est très court, et le IMAGE_OPTIONAL_HEADER, beaucoup plus grand. Voilà donc les structures représentant le PE Header:

Code C :
typedef struct _IMAGE_NT_HEADERS {
DWORD Signature; /* "PE\0\0" */ /* pe_base + 0x00 */
IMAGE_FILE_HEADER FileHeader; /* pe_base + 0x04 */
IMAGE_OPTIONAL_HEADER32 OptionalHeader; /* pe_base + 0x18 */
} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;


et le file header:

Code C :
typedef struct _IMAGE_FILE_HEADER {
WORD Machine; /* pe_base + 0x04 */
WORD NumberOfSections; /* pe_base + 0x06 */
DWORD TimeDateStamp; /* pe_base + 0x08 */
DWORD PointerToSymbolTable; /* pe_base + 0x0c */
DWORD NumberOfSymbols; /* pe_base + 0x10 */
WORD SizeOfOptionalHeader; /* pe_base + 0x14 */
WORD Characteristics; /* pe_base + 0x16 */
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;


Le File Header contient des informations intéressantes comme le nombre de sections de l'exécutable (on y reviendra plus tard), ou encore le champ "Characteristics", qui indique le type du binaire que l'on regarde (si c'est un driver, dll, exécutable...). La description de ces champs est facilement trouvable, il suffit de RTFM un peu Wink
Après le file header, vient l'Optional Header, qui contient une quantité non négligeable d'informations, concernant où l'image de l'exécutable sera placée en mémoire, la taille du code, la taille des données, la RVA du point d'entrée, et plein d'autres choses intéressantes. L'optional header est représentée par la structure suivante:

Code C :

typedef struct _IMAGE_OPTIONAL_HEADER {
    /* Standard fields */
    WORD Magic; /* pe_base + 0x18 */
    BYTE MajorLinkerVersion; /* pe_base + 0x1A */
    BYTE MinorLinkerVersion; /* pe_base + 0x1B */
    DWORD SizeOfCode; /* pe_base + 0x1C */
    DWORD SizeOfInitializedData; /* pe_base + 0x20 */
    DWORD SizeOfUninitializedData; /* pe_base + 0x24 */
    DWORD AddressOfEntryPoint; /* pe_base + 0x28 */
    DWORD BaseOfCode; /* pe_base + 0x2C */
    DWORD BaseOfData; /* pe_base + 0x30 */

    /* NT additional fields */
    DWORD ImageBase; /* pe_base + 0x34 */
    DWORD SectionAlignment;
    DWORD FileAlignment; /* pe_base + 0x3C */
    WORD MajorOperatingSystemVersion; /* pe_base + 0x40 */
    WORD MinorOperatingSystemVersion; /* pe_base + 0x42 */
    WORD MajorImageVersion; /* pe_base + 0x44 */
    WORD MinorImageVersion; /* pe_base + 0x46 */
    WORD MajorSubsystemVersion; /* pe_base + 0x48 */
    WORD MinorSubsystemVersion; /* pe_base + 0x4A */
    DWORD Win32VersionValue; /* pe_base + 0x4C */
    DWORD SizeOfImage; /* pe_base + 0x50 */
    DWORD SizeOfHeaders; /* pe_base + 0x54 */
    DWORD CheckSum; /* pe_base + 0x58 */
    WORD Subsystem; /* pe_base + 0x5C */
    WORD DllCharacteristics; /* pe_base + 0x5E */
    DWORD SizeOfStackReserve; /* pe_base + 0x60 */
    DWORD SizeOfStackCommit; /* pe_base + 0x64 */
    DWORD SizeOfHeapReserve; /* pe_base + 0x68 */
    DWORD SizeOfHeapCommit; /* pe_base + 0x6C */
    DWORD LoaderFlags; /* pe_base + 0x70 */
    DWORD NumberOfRvaAndSizes; /* pe_base + 0x74 */
    IMAGE_DATA_DIRECTORY DataDirectory[16]; /* pe_base + 0x78 */
} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
 


On peut voir à la fin de la structure un tableau de DataDirectory, qui contiennent les RVA vers la table d'imports, d'exports, de ressources ou encore de plein d'autres données (comme par exemple les en-têtes COM/CLR). A noter aussi que la célèbre protection anti-Reflector ne fait que modifier la valeur du champ "NumberOfRvaAndSizes", qui sert normalement à préciser combien de DataDirectory sont présents. A chaque index du tableau de DataDirectory correspond un type de données, ainsi le DataDirectory à l'index 0 correspond à la table d'export, l'index 1 à la table d'import, l'index 2 à la table de ressources...

Références
Mon blog

Code :
push esp ; dec eax ; inc ebp ; and [edi+0x41],al ; dec ebp ; inc ebp

"VIM est merveilleux" © supersnail
+1 (1) -1 (0) Répondre
04-09-2012, 11h18
Message : #2
Swissky Absent
Bon membre
*



Messages : 523
Sujets : 32
Points: 96
Inscription : Apr 2012
RE: Le PE Header - Pour commencer
Lien à remplacer dans les Références : http://repo.aassfxxx.infos.st/docs/windo...ons_PE.pdf Wink
+1 (0) -1 (0) Répondre
04-09-2012, 11h18
Message : #3
supersnail Hors ligne
Éleveur d'ornithorynques
*******



Messages : 1,613
Sujets : 72
Points: 466
Inscription : Jan 2012
RE: Le PE Header - Pour commencer
En effet, merci :p
Mon blog

Code :
push esp ; dec eax ; inc ebp ; and [edi+0x41],al ; dec ebp ; inc ebp

"VIM est merveilleux" © supersnail
+1 (0) -1 (0) Répondre


Sujets apparemment similaires…
Sujet Auteur Réponses Affichages Dernier message
  [C] Multiples arguments pour une fonction appelée dans un Thread Junky 0 800 29-03-2013, 17h55
Dernier message: Junky

Atteindre :


Utilisateur(s) parcourant ce sujet : 2 visiteur(s)
N-PN
Accueil | Challenges | Tutoriels | Téléchargements | Forum | Retourner en haut