[Bug 52119] New: EndUpdateResource calculates field "SizeofImage" wrong

WineHQ Bugzilla wine-bugs at winehq.org
Fri Nov 26 18:29:59 CST 2021


https://bugs.winehq.org/show_bug.cgi?id=52119

            Bug ID: 52119
           Summary: EndUpdateResource calculates field "SizeofImage" wrong
           Product: Wine
           Version: 6.22
          Hardware: x86-64
                OS: Linux
            Status: UNCONFIRMED
          Severity: normal
          Priority: P2
         Component: kernel32
          Assignee: wine-bugs at winehq.org
          Reporter: info at daniel-marschall.de
      Distribution: ---

The function `EndUpdateResource` will calculate the PE field "SizeOfImage" like
this:

For 64 bit:
nt64->OptionalHeader.SizeOfImage += rva_delta;

For 32 bit:
nt->OptionalHeader.SizeOfImage += rva_delta;

But this is wrong. It does not follow the specification of Microsoft, and
therefore, some combinations of SizeofImage values and Windows versions will
cause the Operating System to deny loading the image.

The correct implementation is described here:
https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed

Correct is following code (to be added to `write_raw_resources`):

For 64 bit:

            lastsec = get_last_section(write_map->base, mapping_size);
            pEndOfLastSection = lastsec->VirtualAddress +
lastsec->Misc.VirtualSize + nt64->OptionalHeader.ImageBase;
            //NOTE: we are rounding to memory section alignment, not file
            pEndOfLastSectionMem =
peRoundUpToAlignment64(nt64->OptionalHeader.SectionAlignment,
pEndOfLastSection);
            uCalcSizeOfFile = pEndOfLastSectionMem -
nt64->OptionalHeader.ImageBase;
            nt64->OptionalHeader.SizeOfImage = (DWORD)uCalcSizeOfFile;

For 32 bit:

            //nt->OptionalHeader.SizeOfImage += rva_delta;
            // Fix by Daniel Marschall: Added this calculation of
"SizeOfImage".
            // With the original implementation, Windows won't load some
images!
            //
https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
            lastsec = get_last_section(write_map->base, mapping_size);
            pEndOfLastSection = lastsec->VirtualAddress +
lastsec->Misc.VirtualSize + nt->OptionalHeader.ImageBase;
            //NOTE: we are rounding to memory section alignment, not file
            pEndOfLastSectionMem =
peRoundUpToAlignment(nt->OptionalHeader.SectionAlignment, pEndOfLastSection);
            uCalcSizeOfFile = pEndOfLastSectionMem -
nt->OptionalHeader.ImageBase;
            nt->OptionalHeader.SizeOfImage = uCalcSizeOfFile;


And the required functions:

//
// peRoundUpToAlignment() - rounds dwValue up to nearest dwAlign
//
DWORD peRoundUpToAlignment(DWORD dwAlign, DWORD dwVal)
{
    // Fix by Fix by Daniel Marschall: Added this function, based on
    //
https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
    if (dwAlign)
    {
        //do the rounding with bitwise operations...

        //create bit mask of bits to keep
        //  e.g. if section alignment is 0x1000                       
1000000000000
        //       we want the following bitmask     
11111111111111111111000000000000
        DWORD dwMask = ~(dwAlign - 1);

        //round up by adding full alignment (dwAlign-1 since if already aligned
we don't want anything to change),
        //  then mask off any lower bits
        dwVal = (dwVal + dwAlign - 1) & dwMask;
    }

    return(dwVal);

}

ULONGLONG peRoundUpToAlignment64(ULONGLONG dwAlign, ULONGLONG dwVal)
{
    // Fix by Fix by Daniel Marschall: Added this function, based on
    //
https://stackoverflow.com/questions/39022853/how-is-sizeofimage-in-the-pe-optional-header-computed
    if (dwAlign)
    {
        //do the rounding with bitwise operations...

        //create bit mask of bits to keep
        //  e.g. if section alignment is 0x1000                       
1000000000000
        //       we want the following bitmask     
11111111111111111111000000000000
        ULONGLONG dwMask = ~(dwAlign - 1);

        //round up by adding full alignment (dwAlign-1 since if already aligned
we don't want anything to change),
        //  then mask off any lower bits
        dwVal = (dwVal + dwAlign - 1) & dwMask;
    }

    return(dwVal);

}

static IMAGE_SECTION_HEADER* get_last_section(void* base, DWORD mapping_size)
{
    // Fix by Fix by Daniel Marschall: Added this function which is required by
the "SizeOfImage" field calculation

    IMAGE_SECTION_HEADER* sec;
    IMAGE_NT_HEADERS* nt;
    DWORD num_sections = 0;

    nt = get_nt_header(base, mapping_size);
    if (!nt)
        return NULL;

    sec = get_section_header(base, mapping_size, &num_sections);
    if (!sec)
        return NULL;

    /* find the resources section */
    return &sec[num_sections - 1];
}

-- 
Do not reply to this email, post in Bugzilla using the
above URL to reply.
You are receiving this mail because:
You are watching all bug changes.



More information about the wine-bugs mailing list