Cargando encabezados PE

7 minutos de lectura

Básicamente, lo que intento hacer es encontrar la última sección del archivo PE. He leído la especificación PE con mucha atención, pero no puedo descubrir dónde falla mi código.

PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)(pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)(pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));

buffer es una matriz de bytes que contiene ejecutable cargado, y pish es un puntero a la última sección. Por alguna razón, parece que el número de secciones supera las 20 000.

Algunas ideas ? Gracias por adelantado

  • “No puedo descubrir dónde falla mi código”. – ¿Cómo falla?

    – Trigo Mitch

    9 de enero de 2012 a las 0:40

  • Como dije, el número de secciones supera los 20k. Por lo tanto, al desreferenciar a miembros de pish el programa falla.

    – Kijan

    9 de enero de 2012 a las 0:44

avatar de usuario
jowo

Hay un problema que veo de improviso: e_lfanew es el desplazamiento del IMAGE_NT_HEADERS estructura en bytes. Está agregando este número de bytes a un IMAGE_DOS_HEADER puntero, por lo que se está moviendo hacia adelante sizeof(IMAGE_DOS_HEADER)*pidh->e_lfanew bytes

Versión fija:

PIMAGE_DOS_HEADER pidh = (PIMAGE_DOS_HEADER)buffer;
PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS)((BYTE*)pidh + pidh->e_lfanew);
PIMAGE_FILE_HEADER pifh = (PIMAGE_FILE_HEADER)&pinh->FileHeader;
PIMAGE_OPTIONAL_HEADER pioh = (PIMAGE_OPTIONAL_HEADER)&pinh->OptionalHeader;
PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)((BYTE*)pinh + sizeof(IMAGE_NT_HEADERS) + (pifh->NumberOfSections - 1) * sizeof(IMAGE_SECTION_HEADER));

La mejor manera de depurar problemas como este es acceder al código con su depurador y ver los datos PE usted mismo en la memoria. Puede abrir el editor hexadecimal de Visual Studio, por ejemplo, y ver todos los datos de bytes y qué valores está leyendo en realidad.

Aquí hay información sobre cómo ver la memoria del programa en VS 2010:
http://msdn.microsoft.com/en-us/library/s3aw423e.aspx

  • Bueno, muchas gracias, parece que el problema está en mi (no) conocimiento de la aritmética de punteros. 🙂

    – Kijan

    9 de enero de 2012 a las 2:25

  • @jowo es e_magic desde IMAGE_DOS_HEADER se supone que debe coincidir con el Magic de El IMAGE_FILE_HEADER? Si es así, no sé por qué tengo un comportamiento incorrecto. He cargado mi EXE en un std::vector<char> bytes objeto y trató de establecer IMAGE_DOS_HEADER* img_dos_header = (IMAGE_DOS_HEADER*)&bytes[0]; pero los números mágicos no se alinean con mi IMAGE_FILE_HEADER* coff_file_header = (IMAGE_FILE_HEADER*)&bytes[coff_file_header_offset];, que definitivamente está cargando la información correcta. ¿Alguna idea de lo que necesito arreglar? ¿O una forma alternativa de cargar IMAGE_DOS_HEADER?

    – KayleeFrye_onDeck

    22 mayo 2017 a las 20:46


  • OK entonces, e_magic por IMAGE_DOS_HEADER es en realidad el firma para el formato PE… entonces &bytes[0] en realidad era correcto, evaluando a 0x5A4D 🙂

    – KayleeFrye_onDeck

    22 mayo 2017 a las 22:15


  • Esta fue una buena lectura, por cierto: what-when-how.com/windows-forensic-analysis/…

    – KayleeFrye_onDeck

    22 de mayo de 2017 a las 22:16

  • Ok, última pregunta ^_^ ¿Por qué lanzaste pidh para (BYTE*) al obtener el encabezado NT? Tratando de seguir el proceso de pensamiento para futuras preguntas potenciales.

    – KayleeFrye_onDeck

    22 mayo 2017 a las 22:19


Varias direcciones de sección y datos también se pueden obtener de la siguiente manera:

#include<windows.h>
#include<iostream>

int main()
{
    LPCSTR fileName="inputFile.exe";
    HANDLE hFile;
    HANDLE hFileMapping;
    LPVOID lpFileBase;
    PIMAGE_DOS_HEADER dosHeader;
    PIMAGE_NT_HEADERS peHeader;
    PIMAGE_SECTION_HEADER sectionHeader;

    hFile = CreateFileA(fileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);

    if(hFile==INVALID_HANDLE_VALUE)
    {
        std::cout<<"\n CreateFile failed \n";
        return 1;
    }

    hFileMapping = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,0,NULL);

    if(hFileMapping==0)
    {
        std::cout<<"\n CreateFileMapping failed \n";
        CloseHandle(hFile);
        return 1;
    }

    lpFileBase = MapViewOfFile(hFileMapping,FILE_MAP_READ,0,0,0);

    if(lpFileBase==0)
    {
        std::cout<<"\n MapViewOfFile failed \n";
        CloseHandle(hFileMapping);
        CloseHandle(hFile);
        return 1;
    }

    dosHeader = (PIMAGE_DOS_HEADER) lpFileBase;
    if(dosHeader->e_magic==IMAGE_DOS_SIGNATURE)
    {
        std::cout<<"\n DOS Signature (MZ) Matched \n";

        peHeader = (PIMAGE_NT_HEADERS) ((u_char*)dosHeader+dosHeader->e_lfanew);
        if(peHeader->Signature==IMAGE_NT_SIGNATURE)
        {
            std::cout<<"\n PE Signature (PE) Matched \n";
            sectionHeader = IMAGE_FIRST_SECTION(peHeader);
            UINT nSectionCount = peHeader->FileHeader.NumberOfSections;

            //No of Sections
            std::cout<<"\n No of Sections : "<<nSectionCount<<"  \n";

            //sectionHeader contains pointer to first section
            //sectionHeader++ will move to next section
            for( UINT i=0; i<nSectionCount; ++i, ++sectionHeader )
            {
                std::cout<<"\n-----------------------------------------------\n";
                std::cout<<"\n Section Name : "<<sectionHeader->Name<<" \n";
                //address can be obtained as (PBYTE)lpFileBase+sectionHeader->PointerToRawData
                std::cout<<"\n Size of section data : "<<sectionHeader->Misc.VirtualSize<<" \n";
                std::cout<<"\n-----------------------------------------------\n";
            }

            //Now sectionHeader will have pointer to last section
            //if you add sectionHeader++ in for loop instead of ++sectionHeader it will point to memory after last section

        }
        else
        {
            return 1;
        }
    }
    else
    {
        return 1;
    }
    return 0;
}

Simplemente lo haces de la manera incorrecta. Escribí un código para ti, espero que te ayude. Puede mostrar los datos de la última sección de un archivo PE.

#include <stdio.h>
#include <malloc.h>
#include <windows.h>

void ShowHexData(BYTE *ptr,DWORD len)
{
    int index = 0;
    int i = 0;
    const int width = 16;
    while(index + width < len)
    {
        int i;
        for(i = 0; i < width; ++i)
        {
            printf(" %02X",ptr[index + i]);
        }
        printf("    \t");
        for(i = 0; i < width; ++i)
        {
            if(ptr[index + i] >= 0x20 &&
                        ptr[index + i] <= 0x7F)
            {
                putchar(ptr[index + i]);
            }else{
                putchar('.');
            }
        }
        index += width;
        putchar('\n');
    }

    for(i = 0; index  + i < len; ++ i)
    {
        printf(" %02X",ptr[index + i]);
    }
    while(i < width)
    {
        printf("   ");
        i += 1;
    }
    printf("    \t");
    for(i = 0; index + i < len; ++ i)
    {
        if(ptr[index + i] >= 0x20 &&
                    ptr[index + i] <= 0x7F)
        {
            putchar(ptr[index + i]);
        }else{
            putchar('.');
        }
    }
    putchar('\n');


}
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        printf("Usage : %s filename\n",argv[0]);
        return -1;
    }else{
        FILE *fp = fopen(argv[1],"rb");
        IMAGE_DOS_HEADER DosHeader = {0};
        IMAGE_FILE_HEADER FileHeader = {0};
        IMAGE_SECTION_HEADER SectionHeader = {0};
        DWORD Signature = 0;
        DWORD RawPointerToPeHeader = 0, SizeOfFile = 0;
        DWORD SectionCount = 0;
        DWORD ByteCount = 0;
        BYTE *pData = NULL;
        if(!fp)
        {
            perror("");
            return -1;
        }
        fseek(fp,0,SEEK_END);
        SizeOfFile = ftell(fp);
        if(SizeOfFile <
            sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS))
            goto not_pe_file;
        fseek(fp,0,SEEK_SET);
        fread(&DosHeader,1,sizeof DosHeader,fp);
        if(DosHeader.e_magic != 'M' + 'Z' * 256)
            goto not_pe_file;
        RawPointerToPeHeader = DosHeader.e_lfanew;
        if(SizeOfFile <=
            RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS))
            goto not_pe_file;
        fseek(fp,RawPointerToPeHeader,SEEK_SET);
        fread(&Signature,1,sizeof(DWORD),fp);
        if(Signature != 'P' + 'E' * 256)
            goto not_pe_file;
        fread(&FileHeader,1,sizeof FileHeader,fp);
        if(FileHeader.SizeOfOptionalHeader !=
            sizeof(IMAGE_OPTIONAL_HEADER))
            goto not_pe_file;
        SectionCount = FileHeader.NumberOfSections;
        if(SectionCount == 0)
        {
            printf("No section for this file.\n");
            fclose(fp);
            return -1;
        }
        if(SizeOfFile <=
            RawPointerToPeHeader +
            sizeof(IMAGE_NT_HEADERS) +
            SectionCount * sizeof(IMAGE_SECTION_HEADER))
            goto not_pe_file;
        fseek(fp,
            RawPointerToPeHeader + sizeof(IMAGE_NT_HEADERS) +
            (SectionCount - 1) * sizeof(IMAGE_SECTION_HEADER),
                SEEK_SET);
        fread(&SectionHeader,1,sizeof SectionHeader,fp);

        ByteCount = SectionHeader.Misc.VirtualSize < SectionHeader.PointerToRawData ?
            SectionHeader.Misc.VirtualSize : SectionHeader.PointerToRawData;

        if(ByteCount == 0)
        {
            printf("No data to read for target section.\n");
            fclose(fp);
            return -1;
        }else if(ByteCount + SectionHeader.PointerToRawData > SizeOfFile)
        {
            printf("Bad section data.\n");
            fclose(fp);
            return -1;
        }
        fseek(fp,SectionHeader.PointerToRawData,SEEK_SET);

        pData = (BYTE*)malloc(ByteCount);

        fread(pData,1,ByteCount,fp);

        ShowHexData(pData,ByteCount);
        free(pData);
        fclose(fp);
        return 0;


not_pe_file:
        printf("Not a PE file.\n");
        fclose(fp);
        return -1;
    }


    return 0;
}

En resumen, no sabe dónde están los datos hasta que los analiza de acuerdo con el encabezado del archivo.

puntero de secciones:

PIMAGE_SECTION_HEADER pish = IMAGE_FIRST_SECTION(pinh); // definición en winnt.h

o

PIMAGE_SECTION_HEADER pish = (PIMAGE_SECTION_HEADER)((BYTE*)pioh + pifh->SizeOfOptionalHeader);

el puntero de la última sección es:

PIMAGE_SECTION_HEADER pilsh = &pish[pifh->NumberOfSections-1]

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad