PE (Portable Executable) Con C++

Discussione in 'C++' iniziata da Diolegend, 23 Gennaio 2019.

  1. Diolegend

    Diolegend Fondatore
    Membro dello Staff Fondatore

    Registrato:
    24 Ottobre 2018
    Messaggi:
    6
    "Mi Piace" ricevuti:
    3
    1. Cos'e il PE?

    Il PE sta per Portable Executable e' un formato di file per
    File eseguibili
    File oggetto
    e non solo.

    2. A cosa serve il PE?

    Il PE contiene tutte le informazioni che serve al Loader di Windows per avviare il vostro programma.

    Ogni cosa di qualunque genere ha un'inizio.
    Anche gli programmi hanno un'inizio che e' lo 0.
    Possiamo usare un editor HEX per vedere i BYTES di un programma.

    Questo e' l'inizio del programma , nella sezione Dump ci sono due lettere la M e la Z, se aprite un'altro programma con il HEX Editor vedrete ancora queste due lettere
    Quindi possiamo dire che queste due lettere sono come dire la firma , un marchio di ogni programma.

    IL PE e' strutturato cosi:

    [​IMG]

    Questa e' l'immagine che mi e' piaciuta di piu' , quindi ho scelto questa.

    All'inizio di tutto c'e il DOS HEADER insieme al DOS STUB Che venivano usati quando c'erano i sistemi operativi DOS.
    C'e la signature 4D 5A che nell'ASCII Viene rappresentata come MZ , non fatevi prendere paura per una cosa banale.
    In questa tabella non riporta tutti i dati del DOS Header e mi tocca di nuovo a mettere un'altra immagine


    Ecco l'immagine , vedrete la variabile d_DosHeader->e_magic e cosi via, questi sono i componenti del dos header ma ormai e' obsoleta, soltanto l'ultima e_lfanew serve a qualcosa, ti porta direttamente nel PE HEADER

    Cioe' 0x000 nella tabella.



    Per fare Questo dovete aggiungere l'indirizzo start con quella variabile, non vi preocuppate per ora , dopo vi metto il codice per arrivare in qualunque parte che volete spiegando anche per bene ogni struct e come ci sono arrivato.

    Siamo arrivati finalmente nel file header , ora c'e da dire cosa sono (Machine,Number Sections....)

    Machine - E' l'architettura del computer che il programma viene eseguito.

    #define IMAGE_FILE_MACHINE_UNKNOWN 0 // sconosciuta
    #define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
    #define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
    #define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
    #define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
    #define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
    #define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
    #define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
    #define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
    #define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
    #define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
    #define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
    #define IMAGE_FILE_MACHINE_THUMB 0x01c2
    #define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
    #define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
    #define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
    #define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
    #define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
    #define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64

    Di solito e' la seconda cioe' 0x014c che sta per x86

    NumberOfSections Il numero delle sezioni che il PE dovrà contenere.

    TimeDateStamp Il tempo ma il linker lo imposta come vuole non ha per nulla a che fare con la modifica creazione che si vede su windows.

    PointerToSymbolTable offset per la symbol table (utile solo per debug).

    NumberOfSymbols numero di simboli nella symbol table.

    SizeOfOptionalHeader la grandezza dell'OPTIONAL HEADER.

    Characteristics specifica alcune informazioni sul file:

    Ulteriori informazioni li trovate qui ma in inglese https://msdn.microsoft.com/it-it/library/windows/desktop/ms680313(v=vs.85).aspx

    Dopo questa c'e l'Optional Headers

    Magic questa word identifica lo stato dell'image file, i valori definiti sono:

    #define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b // normale eseguibile 32bit
    #define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b // 64bit
    #define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107 // ROM

    MajorLinkerVersion e MinorLinkerVersion La versione del Linker niente di utile

    SizeOfCode La grandezza del Code (niente di importante).

    SizeOfInitializedData La grandezza di tutte le variabili initializzate (niente di importante).

    SizeOfUninitializedData - idem ma UnitializedDate
    Queste quattro possono essere messe anche disparte.

    AddressOfEntryPoint è un RVA che e' l'entry point del "CODICE" , cosa vuol dire RVA?
    RVA sta per Relative Virtual Address , ci dovete aggiungere l'indirizzo base per trovare il VA

    BaseOfCode BaseAddress per il codice (.text).

    BaseOfData BaseAdress per la sezione data (.data).

    ImageBase contiene l'indirizzo dove comincia il programma, ma di solito il loader non lo segue mai.
    di solito e' 0x00400000
    SectionAlignment Ordina le sezione di solito in 4 KB e deve essere maggiore o uguale di FileAlignment

    FileAlignment specifica l'allineamento del file .

    MajorOperatingSystemVersion e MinorOperatingSystemVersion specificano la versione dell'OS .

    MajorImageVersion e MinorImageVersion versione immagine .

    MajorSubsystemVersion e MinorSubsystemVersion versione sottosistema .

    Queste tre di solito non servono a nulla , perche' il linker li mette anche a caso certe volte i dati, i creatori sono pigri = =.

    Win32VersionValue Deve essere per forza 0 senno il programma non funzionerebbe.

    SizeOfImage Grandezza dell'IMAGE (del programma nella memoria).

    SizeOfHeaders PE + Le sezioni.

    CheckSum Di solito e' 0 , ma i file piu' importanti ci sono , per esempio il dll kernel32.dll che e' 11E97E.

    Subsystem Questa cosa e' banale , subsystem:windows viene avviata l'interfaccia grafica
    subsystem:console quella nostra della console

    DllCharacteristics Parametro molto utile per fare scopi di rottura.

    SizeOfStackReserve specifica la quantità di memoria da riservare per lo stack iniziale del thread.
    Cambiando questo possiamo avere uno stack puo' grande , quella default e' 1000h
    SizeOfStackCommit specifica la quantità di memoria inizialmente presa per il thread iniziale.

    SizeOfHeapReserve specifica la quanità di memoria da riservare per l'heap iniziale del processo.

    SizeOfHeapCommit specifica la quantità di memoria inizialemente presa nel heap del processo.

    LoaderFlags per il debug.

    NumberOfRvaAndSizes Il numero dell'array della Directory quella giu di solito e' 10h cioe' 16.

    DataDirectory Questa array lo usata in quel tutorial per cambiare una funzione winapi in quella nostra
    Qui possiamo trovare di tutto

    #define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
    #define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
    #define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
    #define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
    #define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
    #define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
    #define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
    // IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
    #define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
    #define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
    #define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
    #define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
    #define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
    #define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
    #define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
    #define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor



    Finalmente siamo arrivati nell'ultima parte , cioe' dove si trovano le sezioni.
    Cosa intendo per sezione ?
    - .text e' una sezione dove si trova il codice
    - .data e' una sezione dove si trova i dati
    - .rdata e' una sezione dove si trova i dati read only
    - .bss e' una sezione dove si trova i dati non initializzati
    e cosi' via , tranquilizzatevi vi postero' il codice pian pian per vedere tutte le sezioni ma per ora no.

    BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; // nome sezione max 8 caratteri

    union {
    DWORD PhysicalAddress;
    DWORD VirtualSize;
    } Misc; Non e' molto utile , perche' certe volte il linker mette dei dati sbagliati

    DWORD VirtualAddress; // indica da quale RVA il loader deve mappare la sezione
    DWORD SizeOfRawData; // grandezza della sezione arrotondata in base al file alignement
    DWORD PointerToRawData; // file offset della sezione
    DWORD PointerToRelocations; // negli exe questo campo è sempre 0 dato che non serve (solo per obj)
    DWORD PointerToLinenumbers; // come PointerToRelocations
    WORD NumberOfRelocations; // solo obj
    WORD NumberOfLinenumbers; // mai visto utilizzato manco questo (nei comuni PE dico)
    DWORD Characteristics; // caratteristiche della sezione
    .
    C++:
    Codice (C++):
    #include <iostream>
    #include <Windows.h>

    int main()
    {

        BYTE* d_PeHeader = (BYTE*)GetModuleHandle(0);
        auto rva2va = [&](DWORD dwVa) {
            return (uintptr_t)(dwVa + (uintptr_t)d_PeHeader);
        };
        DWORD* d_Hook = 0;
        auto  d_DosHeader     = (IMAGE_DOS_HEADER       *)d_PeHeader;
        auto  d_NtHeader32    = (IMAGE_NT_HEADERS32     *)rva2va(d_DosHeader->e_lfanew);
        d_NtHeader32->FileHeader;
        d_NtHeader32->OptionalHeader;
        auto  d_SectionHeader = (IMAGE_SECTION_HEADER   *)((uintptr_t)d_NtHeader32 + sizeof(IMAGE_NT_HEADERS32));
        return 0;
    }
     
    IMAGE_DOS_HEADER e' la struct per il DOS_HEADER
    IMAGE_NT_HEADERS32 Contiene a suo interno FileHeader e OptionalHeader
    IMAGE_SECTION_HEADER e' la struct SECTION_HEADER

    Per oggi e' tutto sono un po' stanco, la prossima guida andro piu' in fondo sapendo che voi sapiate il PE.

    Correggetemi se ho sbagliato gli errori grammaticali o anche tecnici , sapete anche voi che fare una guida e' una cosa stancante.
    Grazie.
    - Diolegend
     
    #1 Diolegend, 23 Gennaio 2019
    Ultima modifica: 23 Gennaio 2019

Condividi questa Pagina