c++ pe loader, runna i tuoi exe in memoria senza triggerare l'av

monnezzza

Utente Silver
11 Marzo 2021
119
23
53
86
stavo scrivendo un pe loader in c++ ma non ci sono ma l'exe non viene eseguito. Il codice è questo.
Descrizione:
Il programma inizia controllando se è stato fornito un percorso per il file PE come argomento sulla riga di comando. Se non è stato fornito alcun percorso, il programma restituisce un messaggio di errore e termina.

Successivamente, il programma apre il file PE in modalità binaria e alloca memoria per l'intero file. Se il file non può essere aperto, il programma restituisce un messaggio di errore e termina. Se la memoria non può essere allocata, il programma restituisce un messaggio di errore e termina.

Il programma verifica quindi se il file PE è valido. Per fare ciò, legge l'intestazione DOS dal buffer del file e verifica che la firma sia corretta. Se la firma non è corretta, il programma restituisce un messaggio di errore e termina. Se la firma è corretta, il programma cerca l'intestazione NT e verifica che la firma sia corretta. Se la firma non è corretta, il programma restituisce un messaggio di errore e termina.

Il programma calcola quindi la dimensione dell'immagine dal campo SizeOfImage dell'header opzionale NT e alloca memoria per l'immagine. Se la memoria non può essere allocata, il programma restituisce un messaggio di errore e termina.

Il programma copia quindi l'header dell'immagine dal buffer del file all'indirizzo dell'immagine. Copia anche le sezioni dell'immagine dal buffer del file alle loro posizioni nell'immagine. Per fare ciò, il programma itera attraverso ogni sezione nell'header delle sezioni e copia la sezione dal buffer del file all'indirizzo dell'immagine.

Il programma ottiene quindi il punto di ingresso dell'immagine dal campo AddressOfEntryPoint dell'header opzionale NT e lo esegue. Per fare ciò, il programma converte l'indirizzo del punto di ingresso in un puntatore a una funzione che restituisce un intero. Il programma quindi chiama la funzione e memorizza il risultato.

Infine, il programma libera la memoria allocata per l'immagine e per il buffer del file e stampa il risultato.
Codice:
C++:
#include <windows.h>
#include <iostream>
#include <fstream>

int main(int argc, char** argv) {

    // Check that a path to a PE file was provided
    if (argc < 2) {
        std::cerr << "Usage: " << argv[0] << " <path_to_pe_file>" << std::endl;
        return 1;
    }

    // Open the PE file
    std::ifstream pe_file(argv[1], std::ios::binary | std::ios::ate);
    if (!pe_file.is_open()) {
        std::cerr << "Error opening file: " << argv[1] << std::endl;
        return 1;
    }

    // Get the file size and allocate memory
    std::streamsize size = pe_file.tellg();
    char* pe_buffer = new char[size];
    pe_file.seekg(0, std::ios::beg);
    pe_file.read(pe_buffer, size);
    pe_file.close();

    // Check that the memory allocation was successful
    if (!pe_buffer) {
        std::cerr << "Error allocating memory." << std::endl;
        return 1;
    }

    // Check if the file is a valid PE file
    IMAGE_DOS_HEADER* dos_header = (IMAGE_DOS_HEADER*) pe_buffer;
    if (dos_header->e_magic != IMAGE_DOS_SIGNATURE) {
        std::cerr << "Invalid PE file." << std::endl;
        delete[] pe_buffer;
        return 1;
    }

    // Get the NT headers
    IMAGE_NT_HEADERS* nt_headers = (IMAGE_NT_HEADERS*) (pe_buffer + dos_header->e_lfanew);

    // Check if the NT headers are valid
    if (nt_headers->Signature != IMAGE_NT_SIGNATURE) {
        std::cerr << "Invalid PE file." << std::endl;
        delete[] pe_buffer;
        return 1;
    }

    // Calculate the size of the image
    DWORD image_size = nt_headers->OptionalHeader.SizeOfImage;

    // Allocate memory for the image
    LPVOID image_base = VirtualAlloc(NULL, image_size, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

    // Check that the memory allocation was successful
    if (!image_base) {
        std::cerr << "Error allocating memory." << std::endl;
        delete[] pe_buffer;
        return 1;
    }

    // Copy the headers to the image
    memcpy(image_base, pe_buffer, nt_headers->OptionalHeader.SizeOfHeaders);

    // Copy the sections to the image
    IMAGE_SECTION_HEADER* section_header = IMAGE_FIRST_SECTION(nt_headers);
    for (int i = 0; i < nt_headers->FileHeader.NumberOfSections; i++, section_header++) {
        memcpy((char*) image_base + section_header->VirtualAddress, pe_buffer + section_header->PointerToRawData, section_header->SizeOfRawData);
    }

    // Get the entry point of the image
    DWORD entry_point = nt_headers->OptionalHeader.AddressOfEntryPoint + (DWORD) image_base;

    // Call the entry point of the image
    typedef int (*EntryPoint)();
    EntryPoint ep = (EntryPoint) entry_point;
    int result = ep();

    // Free the memory
    VirtualFree(image_base, 0, MEM_RELEASE);
    delete[] pe_buffer;

    // Print the result of the entry point
    std::cout << "Result: " << result << std::endl;

    return 0;
}
 
Se volevi chiedere come fare un loader PE potevi farlo direttamente senza pubblicare questa roba, chiaramente partorita da ChatGPT.

Non dovresti allocare tutte le sezioni in un unica area contigua RWX, ma seguire gli header delle sezioni, poi manca la gestione delle relocation e della import address table (e se il tuo exe le usa, exception directory, TLS callback e delayed import), altrimenti avrai un crash dentro int result = ep();.
 
Se volevi chiedere come fare un loader PE potevi farlo direttamente senza pubblicare questa roba, chiaramente partorita da ChatGPT.

Non dovresti allocare tutte le sezioni in un unica area contigua RWX, ma seguire gli header delle sezioni, poi manca la gestione delle relocation e della import address table (e se il tuo exe le usa, exception directory, TLS callback e delayed import), altrimenti avrai un crash dentro int result = ep();.
Hahaha sisi è stata partorita da chat gpt🤣🤣🤣