VirtualBox

Changeset 105153 in vbox


Ignore:
Timestamp:
Jul 5, 2024 2:06:36 AM (8 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
163787
Message:

bldprogs/VBoxPeSetVersion: Calc checksum when we change stuff to avoid triggering overzealous AV scanners.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/bldprogs/VBoxPeSetVersion.cpp

    r98103 r105153  
    5252static const char *g_pszFilename;
    5353static unsigned    g_cVerbosity = 0;
     54static enum { kUpdateCheckSum_Never, kUpdateCheckSum_WhenNeeded, kUpdateCheckSum_Always, kUpdateCheckSum_Zero }
     55                   g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded;
    5456
    5557
     
    8082
    8183
     84/**
     85 * File size.
     86 *
     87 * @returns file size in bytes.
     88 * @returns 0 on failure.
     89 * @param   pFile   File to size.
     90 */
     91static size_t fsize(FILE *pFile)
     92{
     93    long    cbFile;
     94    off_t   Pos = ftell(pFile);
     95    if (    Pos >= 0
     96        &&  !fseek(pFile, 0, SEEK_END))
     97    {
     98        cbFile = ftell(pFile);
     99        if (    cbFile >= 0
     100            &&  !fseek(pFile, 0, SEEK_SET))
     101            return cbFile;
     102    }
     103    return 0;
     104}
     105
     106
     107/**
     108 * Calculates a raw PE-style checksum on a plain buffer.
     109 *
     110 * ASSUMES pvBuf is dword aligned.
     111 */
     112static uint16_t CalcRawPeChecksum(void const *pvBuf, size_t cb, uint32_t uChksum)
     113{
     114    /*
     115     * Work thru the memory in 64 bits at a time.
     116     * ASSUMES well aligned input.
     117     */
     118    uint64_t        uBigSum = uChksum;
     119    uint64_t const *pu64    = (uint64_t const *)pvBuf;
     120    size_t          cQWords = cb / 8;
     121    while (cQWords-- > 0)
     122    {
     123        /* We emulate add with carry here. */
     124        uint64_t uTmp = uBigSum + *pu64++;
     125        uBigSum = uTmp >= uBigSum ? uTmp : uTmp + 1;
     126    }
     127
     128    /*
     129     * Zeropadd any remaining bytes before adding them.
     130     */
     131    if (cb & 7)
     132    {
     133        uint8_t const *pb     = (uint8_t const *)pu64;
     134        uint64_t       uQWord = 0;
     135        switch (cb & 7)
     136        {
     137            case 7: uQWord |= (uint64_t)pb[6] << 48; RT_FALL_THRU();
     138            case 6: uQWord |= (uint64_t)pb[5] << 40; RT_FALL_THRU();
     139            case 5: uQWord |= (uint64_t)pb[4] << 32; RT_FALL_THRU();
     140            case 4: uQWord |= (uint64_t)pb[3] << 24; RT_FALL_THRU();
     141            case 3: uQWord |= (uint64_t)pb[2] << 16; RT_FALL_THRU();
     142            case 2: uQWord |= (uint64_t)pb[1] <<  8; RT_FALL_THRU();
     143            case 1: uQWord |= (uint64_t)pb[0]; break;
     144        }
     145
     146        uint64_t uTmp = uBigSum + uQWord;
     147        uBigSum = uTmp >= uBigSum ? uTmp : uTmp + 1;
     148    }
     149
     150    /*
     151     * Convert the 64-bit checksum to a 16-bit one.
     152     */
     153    uChksum =  (uBigSum        & 0xffffU)
     154            + ((uBigSum >> 16) & 0xffffU)
     155            + ((uBigSum >> 32) & 0xffffU)
     156            + ((uBigSum >> 48) & 0xffffU);
     157    uChksum = (uChksum         & 0xffffU)
     158            + (uChksum >> 16);
     159    if (uChksum > 0xffffU) Error("Checksum IPE#1");
     160    return uChksum & 0xffffU;
     161}
     162
     163
     164static int UpdateChecksum(FILE *pFile)
     165{
     166    /*
     167     * Read the whole file into memory.
     168     */
     169    size_t const    cbFile = fsize(pFile);
     170    if (!cbFile)
     171        return Error("Failed to determine file size: %s", strerror(errno));
     172    uint8_t * const pbFile = (uint8_t *)malloc(cbFile + 4);
     173    if (!pbFile)
     174        return Error("Failed to allocate %#lx bytes for checksum calculations", (unsigned long)(cbFile + 4U));
     175    memset(pbFile, 0, cbFile + 4);
     176
     177    int        rcExit;
     178    size_t     cItemsRead = fread(pbFile, cbFile, 1, pFile);
     179    if (cItemsRead == 1)
     180    {
     181        /*
     182         * Locate the NT headers as we need the CheckSum field in order to update it.
     183         * It has the same location in 32-bit and 64-bit images.
     184         */
     185        IMAGE_DOS_HEADER const   * const pMzHdr  = (IMAGE_DOS_HEADER const *)pbFile;
     186        AssertCompileMembersAtSameOffset(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum, IMAGE_NT_HEADERS64, OptionalHeader.CheckSum);
     187        IMAGE_NT_HEADERS32 * const       pNtHdrs
     188            = (IMAGE_NT_HEADERS32 *)&pbFile[pMzHdr->e_magic == IMAGE_DOS_SIGNATURE ? pMzHdr->e_lfanew : 0];
     189        if ((uintptr_t)&pNtHdrs->OptionalHeader.DataDirectory[0] - (uintptr_t)pbFile < cbFile)
     190        {
     191            if (   pNtHdrs->Signature == IMAGE_NT_SIGNATURE
     192                && (   pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
     193                    || pNtHdrs->OptionalHeader.Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC))
     194            {
     195                /*
     196                 * Set the checksum field to zero to avoid having to do tedious
     197                 * adjustments of the raw checksum. Then calculate the raw check sum.
     198                 */
     199                pNtHdrs->OptionalHeader.CheckSum = 0;
     200                uint32_t uChksum = CalcRawPeChecksum(pbFile, RT_ALIGN_Z(cbFile, 2), 0);
     201
     202                /* Finalize the checksum by adding the image size to it. */
     203                uChksum += (uint32_t)cbFile;
     204                pNtHdrs->OptionalHeader.CheckSum = uChksum;
     205
     206                /*
     207                 * Write back the checksum to the file.
     208                 */
     209                size_t const offChecksumField = (uintptr_t)&pNtHdrs->OptionalHeader.CheckSum - (uintptr_t)pbFile;
     210
     211                if (fseek(pFile, (long)offChecksumField, SEEK_SET) == 0)
     212                {
     213                    if (fwrite(&pNtHdrs->OptionalHeader.CheckSum, sizeof(pNtHdrs->OptionalHeader.CheckSum), 1, pFile) == 1)
     214                    {
     215                        Info(1, "Checksum: %#x", uChksum);
     216                        rcExit = RTEXITCODE_SUCCESS;
     217                    }
     218                    else
     219                        rcExit = Error("Checksum write failed");
     220                }
     221                else
     222                    rcExit = Error("Failed seeking to %#lx for checksum write", (long)offChecksumField);
     223            }
     224            else
     225                rcExit = Error("PE header not found");
     226        }
     227        else
     228            rcExit = Error("NT headers not within file when checksumming");
     229    }
     230    else
     231        rcExit = Error("Failed read in file (%#lx bytes) for checksum calculations", (unsigned long)(cbFile + 4U));
     232
     233    free(pbFile);
     234    return rcExit;
     235}
     236
     237
    82238static int UpdateFile(FILE *pFile, unsigned uNtVersion, PIMAGE_SECTION_HEADER *ppaShdr)
    83239{
     240    unsigned cFileModifications = 0;
     241
    84242    /*
    85243     * Locate and read the PE header.
     
    182340        if (fwrite(&NtHdrsNew, cbNewHdrs, 1, pFile) != 1)
    183341            return Error("Failed to write PE header at %#lx: %s", offNtHdrs, strerror(errno));
    184     }
     342        cFileModifications++;
     343    }
     344    else
     345        Info(3, "No header changes");
    185346
    186347    /*
     
    246407                        return Error("Failed to write %8.8s section header header at %#lx: %s",
    247408                                     paShdrs[i].Name, offShdr, strerror(errno));
     409                    cFileModifications++;
    248410                    if (uRvaIat == UINT32_MAX && fFoundBss)
    249411                        break;
     
    253415                uRvaEnd = paShdrs[i].VirtualAddress;
    254416            }
    255 
     417    }
     418
     419    /*
     420     * Recalculate the checksum if we changed anything or if it is zero.
     421     */
     422    if (   g_enmUpdateChecksum == kUpdateCheckSum_Always
     423        || (   g_enmUpdateChecksum == kUpdateCheckSum_WhenNeeded
     424            && (cFileModifications || NtHdrsNew.x32.OptionalHeader.CheckSum == 0)))
     425        return UpdateChecksum(pFile);
     426
     427    /* Zero the checksum if explicitly requested. */
     428    if (   g_enmUpdateChecksum == kUpdateCheckSum_Zero
     429        && NtHdrsNew.x32.OptionalHeader.CheckSum != 0)
     430    {
     431        unsigned long const offCheckSumField = offNtHdrs + RT_UOFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
     432        if (fseek(pFile, offCheckSumField, SEEK_SET) != 0)
     433            return Error("Failed to seek to the CheckSum field in the PE at %#lx: %s", offCheckSumField, strerror(errno));
     434
     435        NtHdrsNew.x32.OptionalHeader.CheckSum = 0;
     436        if (fwrite(&NtHdrsNew.x32.OptionalHeader.CheckSum, sizeof(NtHdrsNew.x32.OptionalHeader.CheckSum), 1, pFile) != 1)
     437            return Error("Failed to write the CheckSum field in the PE header at %#lx: %s", offCheckSumField, strerror(errno));
    256438    }
    257439
     
    271453            "  --nt31, --nt350, --nt351, --nt4, --w2k, --xp, --w2k3, --vista,\n"
    272454            "  --w7, --w8, --w81, --w10\n"
    273             "    Which version to set.  Default: --nt31\n"
     455            "    Which version to set.  Default: --nt31 (x86), --w2k3 (amd64)\n"
     456            "  --update-checksum-when-needed, --always-update-checksum,\n"
     457            "  --never-update-checksum, --zero-checksum:\n"
     458            "    Checksum updating. Default: --update-checksum-when-needed\n"
    274459            );
    275460    return RTEXITCODE_SYNTAX;
     
    336521                    else if (strcmp(psz, "w10") == 0)
    337522                        uNtVersion = MK_VER(10,0);
     523                    else if (strcmp(psz, "always-update-checksum") == 0)
     524                        g_enmUpdateChecksum = kUpdateCheckSum_Always;
     525                    else if (strcmp(psz, "never-update-checksum") == 0)
     526                        g_enmUpdateChecksum = kUpdateCheckSum_Never;
     527                    else if (strcmp(psz, "update-checksum-when-needed") == 0)
     528                        g_enmUpdateChecksum = kUpdateCheckSum_WhenNeeded;
     529                    else if (strcmp(psz, "zero-checksum") == 0)
     530                        g_enmUpdateChecksum = kUpdateCheckSum_Zero;
    338531                    else
    339532                    {
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette