int ParseImage()

in lsvmutils/peimage.c [152:318]


int ParseImage(
    Image* image,
    IN const void* imageData,
    IN UINTN imageSize)
{
    int status = 0;
    unsigned int i;
    EFI_IMAGE_SECTION_HEADER *sections = NULL;
    EFI_IMAGE_DOS_HEADER *dos_hdr = (void *)imageData;
    unsigned int pe_hdr_offset;
    EFI_IMAGE_NT_HEADERS64* pe_hdr;
    EFI_IMAGE_DATA_DIRECTORY* sec_dir;

    /* Check parameters */
    if (!imageData || imageSize < sizeof(EFI_IMAGE_DOS_HEADER) || !image)
    {
        status = -1;
        goto done;
    }

    /* Initialize the image */
    Memset(image, 0, sizeof(Image));
    image->imageData = imageData;
    image->imageSize = imageSize;

    /* Check header magic number */
    if (dos_hdr->e_magic != EFI_IMAGE_DOS_SIGNATURE)
    {
        status = -1;
        goto done;
    }

    /* Set a pointer to the PE header */
    pe_hdr_offset = dos_hdr->e_lfanew;
    pe_hdr = (EFI_IMAGE_NT_HEADERS64*)((UINT8*)imageData + pe_hdr_offset);

    /* Region 1: up to (but not including) the checksum */
    {
        const void* p = imageData;
        UINTN n = (char*)&pe_hdr->OptionalHeader.CheckSum - (char*)imageData;

        if (_AppendRegion(image, p, n) != 0)
        {
            status = -1;
            goto done;
        }
    }


    /* Set a pointer to the security directory entry (holds signature) */
    sec_dir = &pe_hdr->OptionalHeader.DataDirectory[
        EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];

    /* Save the digital signature data (do not add to regions list) */
    if (_ParseSignature(image, sec_dir->VirtualAddress, sec_dir->Size) != 0)
    {
        status = -1;
        goto done;
    }

    /* Region 2: from after checksum up to security directory entry */
    {
        const void* p = (char*)&pe_hdr->OptionalHeader.CheckSum + sizeof(int);
        UINTN n = (char*)sec_dir - (char*)p;

        if (_AppendRegion(image, p, n) != 0)
        {
            status = -1;
            goto done;
        }
    }

    /* Region 3: end of certificate table to end of imageData header */
    {
        const void* p = sec_dir + 1;
        UINTN n = pe_hdr->OptionalHeader.SizeOfHeaders - 
            ((char*)p - (char*)imageData);

        if (_AppendRegion(image, p, n) != 0)
        {
            status = -1;
            goto done;
        }
    }

    /* Sort the section headers (in auxilliary storage) */
    {
        int i;
        int j;

        if (!(sections = (EFI_IMAGE_SECTION_HEADER *)Calloc(
            pe_hdr->FileHeader.NumberOfSections,
            sizeof(EFI_IMAGE_SECTION_HEADER))))
        {
            status = -1;
            goto done;
        }

        Memcpy(sections, 
            (char*)imageData + 
            pe_hdr_offset + 
            sizeof(UINT32) +
            sizeof(EFI_IMAGE_FILE_HEADER) + 
            pe_hdr->FileHeader.SizeOfOptionalHeader,
            pe_hdr->FileHeader.NumberOfSections * 
            sizeof(EFI_IMAGE_SECTION_HEADER));

        for (i = 0; i < pe_hdr->FileHeader.NumberOfSections - 1; i++)
        {
            for (j = 0; j < pe_hdr->FileHeader.NumberOfSections - 1; j++)
            {
                if (_compare(&sections[j], &sections[j+1]) > 0)
                {
                    EFI_IMAGE_SECTION_HEADER tmp = sections[j];
                    sections[j] = sections[j+1];
                    sections[j+1] = tmp;
                }
            }
        }
    }

    /* Add a region for each section */
    for (i = 0; i < pe_hdr->FileHeader.NumberOfSections; i++) 
    {
        EFI_IMAGE_SECTION_HEADER *section = &sections[i];

        if (section->SizeOfRawData)
        {
            const void* p = (char*)imageData + section->PointerToRawData;
            UINTN n = section->SizeOfRawData;

            if (_AppendRegion(image, p, n) != 0)
            {
                status = -1;
                goto done;
            }
        }
    }

    /* Add a region for whatever follows the final section */
    {
        EFI_IMAGE_SECTION_HEADER *section = 
            &sections[pe_hdr->FileHeader.NumberOfSections-1];
        unsigned int offset = 
            section->PointerToRawData + section->SizeOfRawData;

        /* Hash data following the sections */
        if (offset < imageSize)
        {
            const void* p = (char*)imageData + offset;
            UINTN n = imageSize - sec_dir->Size - offset;

            if (_AppendRegion(image, p, n) != 0)
            {
                status = -1;
                goto done;
            }
        }
    }

done:

    if (sections)
        Free(sections);

    return status;
}