Portable Executable (PE) är ett filformat för exekverbarafiler, objektkod och sharedobjects(dll:er) som utvecklades av Microsoft för användning i deras operativsystem Windows NT. Det är baserat på COFF(Common Object File Format) som introducerades i Unix System V r3. Den största skillnaden är att COFF enbart tillåter ett visst antal sektioner medans PE inte har någon begränsning.

filstruktur:
(PE)
[ DOS HEADER (aka MZ header) ]
[ LONG INT ]------------+
... |
[ PE SIGNATUREN ]-------+
[ FILE HEADER ]
[ OPTIONAL HEADER ]
[ SECTION HEADER ]
[ SECTION DATA ]

DOSHEADER:(0x3c byte)
Den här delen är en gammal relik från DOS tiden och är nästan helt ignorerad utav PEladdare, Intressant att notera är dock att om den inte finns så laddas inte PE filen. det behöver inte vara en fullständig MZheader, det räcker med dom första två bytesen ("MZ"), det betyder att man har 58 byte att spara hemlig porr på om man behöver. (ni kan se ett exempel i appendix). Jag tänker inte gå in närmare på vad alla delar av headern betyder då förlegat bara är förnamnet.

LONG INT:(0x4 byte)
direkt efter dosheadern ligger en long int(DWORD), som innehåller en offset från början av filen till PEsignaturen. den är oftast satt till en ganska bra bit efter MZheadern, det är för att få plats med kod som visar ett medelande liknande "This program cannot be run in DOS mode." om programmet skulle köras i DOS. (NOT ibland anses offseten vara en del av MZ headern)

PE SIGNATUREN:
4 byte som ska vara satt till "PE\0\0" på little endian system och "\0\0PE" på big endian. värdet används förutom att avgöra vilken byte order som används för att kontrolera att det är en riktig PEfil.

FILE HEADER:
det här headern är näst intill identisk med fileheadern i COFF, förutom att den första WORDen i PE används för att avgöra vilken maskinvara programmet är skapat för medans den i COFF används som magic number. vilket kanske inte är helt självklart eftersom det magiskavärdet för COFF(0x14c) representerar Intel 386 processorer i PE.
CODE
struct {
  unsigned short f_magic;         /* magisktnummer / maskin          */
  unsigned short f_nscns;         /* antalet sektioner               */
  unsigned long  f_timdat;        /* datum                     */
  unsigned long  f_symptr;        /* offset till symboltabell        */
  unsigned long  f_nsyms;         /* antal poster i symboltabellen   */
  unsigned short f_opthdr;        /* sizeof(optional header)         */
  unsigned short f_flags;         /* flaggor                         */
};

f_magic är satt till något av följande värden:
0x14c - intel 386
0x14d - intel 486
0x14e - intel 586 (aka pentium)
0x160 - R3000 MIPS (little endian)
0x162 - R3000 MIPS (big endian)
0x166 - R4000 MIPS
0x168 - R10000 MIPS
0x184 - DEC Alpha AXP
0x1F0 - IBM PowerPC
intel 386 är nästan uteslutande det som används, men dom andra är också giltiga värden. trots att det inte alltid finns stöd för PE på dessa platformar.

f_nscns visar hur många sektioner det finns i filen, mer om detta senare.

f_timdat det här ska vara satt till datumet filen skapdes, men så ser inte verkligenheten ut den är ofast fylld med nollor eller något som verkar helt slumpmässigt.

f_symptr är en offset till symboltabellen som innehåller debug information om filen, ofast ser man den satt till 0.
f_nsyms antalet poster i symboltabellen, även denna är ofast satt till 0

f_opthdr ska vara satt till storleken på den inte alls så valfria optional header, konstant värde. [ KOLLA UPP ]

f_flags är en bitmask som innehåller lite smått och gott.
0000 0000 0000 0001b - strippade relocs (innuti sektionerna)
0000 0000 0000 0010b - filen är en exe
0000 0000 0000 0100b - kodrads information är borttagen
0000 0000 0000 1000b - debugsymbolerna är borttagna
- till hit är det COFF flaggor -
0000 0000 0001 0000b - programmets RAM kan "swappas" mycket

0000 0000 1000 0000b - oväntad byteorder (big endian på little endian)
0000 0001 0000 0000b - 32bitars maskin
0000 0010 0000 0000b - filen kan enbart köras på sin standard basadress
0000 0100 0000 0000b - filen kan inte köras från cd-rom/floppy etc, kommer kopieras till swap
0000 1000 0000 0000b - filen kan inte köras över nätverk, kommer kopieras till swap
0001 0000 0000 0000b - filen är en drivrutin eller annan systemfil
0010 0000 0000 0000b - filen är en dll
0100 0000 0000 0000b - filen kan inte köras på multiprocessor system
1000 0000 0000 0000b - oväntad byteorder (little endian på big endian)


APPENDIX A:
ett c program som lagrar lite text i MZ utan att förstöra PE imagen.
CODE
#include <stdio.h>
#include <string.h>

typedef unsigned short int WORD;
typedef unsigned long int DWORD;
typedef struct _MZHEADER {
    WORD   e_magic;
    WORD   e_cblp;
    WORD   e_cp;
    WORD   e_crlc;
    WORD   e_cparhdr;
    WORD   e_minalloc;
    WORD   e_maxalloc;
    WORD   e_ss;
    WORD   e_sp;
    WORD   e_csum;
    WORD   e_ip;
    WORD   e_cs;
    WORD   e_lfarlc;
    WORD   e_ovno;
    WORD   e_res[4];
    WORD   e_oemid;
    WORD   e_oeminfo;
    WORD   e_res2[10];
} MZHEADER;

int main(int argc, char **argv){
    FILE *in;
    FILE *out;
    long new;
    MZHEADER mz;
    char tmp = 0x0;
    int i;

    if(argc!=3)
        return 0;
    in = fopen(argv[1], "r");
    out = fopen(argv[2], "w");

    fseek(in, sizeof(MZHEADER), SEEK_SET);
    fread(&new, sizeof(long), 1, in);
    fseek(in, new, SEEK_SET);
    memset(&mz, 0x0, sizeof(MZHEADER));
    strcpy((char*)&mz, "SweZine SweZine SweZine SweZine SweZine SweZine. hemlig porr");
    mz.e_magic = 0x5A4D;
    fwrite(&mz, sizeof(MZHEADER), 1, out);
    fwrite(&new, sizeof(long), 1, out);
    for(i = 0; i < (new - sizeof(MZHEADER)-sizeof(long)); i++){
        fwrite(&tmp, sizeof(char), 1, out);
    }
    while(fread(&mz, sizeof(MZHEADER), 1, in)!=0){
        fwrite(&mz, sizeof(MZHEADER), 1, out);
    }
}