VirtualBox

忽略:
時間撮記:
2014-7-1 下午06:14:02 (10 年 以前)
作者:
vboxsync
訊息:

Merged in iprt++ dev branch.

位置:
trunk
檔案:
修改 3 筆資料

圖例:

未更動
新增
刪除
  • trunk

  • trunk/src/VBox

  • trunk/src/VBox/Runtime/common/ldr/ldrPE.cpp

    r49044 r51770  
    3333#include "internal/iprt.h"
    3434
    35 #include <iprt/alloc.h>
    3635#include <iprt/assert.h>
     36#include <iprt/asm.h>
     37#include <iprt/err.h>
    3738#include <iprt/log.h>
     39#include <iprt/md5.h>
     40#include <iprt/mem.h>
    3841#include <iprt/path.h>
     42#include <iprt/sha.h>
    3943#include <iprt/string.h>
    40 #include <iprt/err.h>
     44#ifndef IPRT_WITHOUT_LDR_VERIFY
     45# include <iprt/crypto/pkcs7.h>
     46# include <iprt/crypto/spc.h>
     47# include <iprt/crypto/x509.h>
     48#endif
    4149#include <iprt/formats/codeview.h>
    4250#include "internal/ldrPE.h"
     
    5361 */
    5462#define PE_RVA2TYPE(pvBits, rva, type)  ((type) ((uintptr_t)pvBits + (uintptr_t)(rva)) )
     63
     64/** The max size of the security directory. */
     65#ifdef IN_RING3
     66# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE   _4M
     67#else
     68# define RTLDRMODPE_MAX_SECURITY_DIR_SIZE   _1M
     69#endif
    5570
    5671
     
    92107    /** The image timestamp. */
    93108    uint32_t                uTimestamp;
     109    /** Set if the image is 64-bit, clear if 32-bit. */
     110    bool                    f64Bit;
    94111    /** The import data directory entry. */
    95112    IMAGE_DATA_DIRECTORY    ImportDir;
     
    100117    /** The debug directory entry. */
    101118    IMAGE_DATA_DIRECTORY    DebugDir;
    102 } RTLDRMODPE, *PRTLDRMODPE;
     119    /** The security directory entry. */
     120    IMAGE_DATA_DIRECTORY    SecurityDir;
     121
     122    /** Offset of the first PKCS \#7 SignedData signature if present. */
     123    uint32_t                offPkcs7SignedData;
     124    /** Size of the first PKCS \#7 SignedData. */
     125    uint32_t                cbPkcs7SignedData;
     126
     127    /** Copy of the optional header field DllCharacteristics. */
     128    uint16_t                fDllCharacteristics;
     129} RTLDRMODPE;
     130/** Pointer to the instance data for a PE loader module. */
     131typedef RTLDRMODPE *PRTLDRMODPE;
     132
    103133
    104134/**
     
    132162
    133163
     164/**
     165 * PE hash context union.
     166 */
     167typedef union RTLDRPEHASHCTXUNION
     168{
     169    RTSHA512CONTEXT Sha512;
     170    RTSHA256CONTEXT Sha256;
     171    RTSHA1CONTEXT   Sha1;
     172    RTMD5CONTEXT    Md5;
     173} RTLDRPEHASHCTXUNION;
     174/** Pointer to a PE hash context union. */
     175typedef RTLDRPEHASHCTXUNION *PRTLDRPEHASHCTXUNION;
     176
     177
     178/**
     179 * PE hash digests
     180 */
     181typedef union RTLDRPEHASHRESUNION
     182{
     183    uint8_t abSha512[RTSHA512_HASH_SIZE];
     184    uint8_t abSha256[RTSHA256_HASH_SIZE];
     185    uint8_t abSha1[RTSHA1_HASH_SIZE];
     186    uint8_t abMd5[RTMD5_HASH_SIZE];
     187} RTLDRPEHASHRESUNION;
     188/** Pointer to a PE hash work set. */
     189typedef RTLDRPEHASHRESUNION *PRTLDRPEHASHRESUNION;
     190
     191/**
     192 * Special places to watch out for when hashing a PE image.
     193 */
     194typedef struct RTLDRPEHASHSPECIALS
     195{
     196    uint32_t    cbToHash;
     197    uint32_t    offCksum;
     198    uint32_t    cbCksum;
     199    uint32_t    offSecDir;
     200    uint32_t    cbSecDir;
     201    uint32_t    offEndSpecial;
     202} RTLDRPEHASHSPECIALS;
     203/** Pointer to the structure with the special hash places. */
     204typedef RTLDRPEHASHSPECIALS *PRTLDRPEHASHSPECIALS;
     205
     206
     207#ifndef IPRT_WITHOUT_LDR_VERIFY
     208/**
     209 * Parsed signature data.
     210 */
     211typedef struct RTLDRPESIGNATURE
     212{
     213    /** The outer content info wrapper. */
     214    RTCRPKCS7CONTENTINFO        ContentInfo;
     215    /** Pointer to the decoded SignedData inside the ContentInfo member. */
     216    PRTCRPKCS7SIGNEDDATA        pSignedData;
     217    /** Pointer to the indirect data content. */
     218    PRTCRSPCINDIRECTDATACONTENT pIndData;
     219    /** The digest type employed by the signature. */
     220    RTDIGESTTYPE                enmDigest;
     221
     222    /** Pointer to the raw signatures.  This is allocated in the continuation of
     223     * this structure to keep things simple.  The size is given by  the security
     224     * export directory. */
     225    WIN_CERTIFICATE const      *pRawData;
     226
     227    /** Hash scratch data. */
     228    RTLDRPEHASHCTXUNION         HashCtx;
     229    /** Hash result. */
     230    RTLDRPEHASHRESUNION         HashRes;
     231} RTLDRPESIGNATURE;
     232/** Pointed to SigneData parsing stat and output. */
     233typedef RTLDRPESIGNATURE *PRTLDRPESIGNATURE;
     234#endif
     235
     236
    134237/*******************************************************************************
    135238*   Internal Functions                                                         *
     
    251354        {
    252355            if ((RTFOFF)offFile + cbToRead > cbFile)
    253                 cbToRead = cbFile - (RTFOFF)offFile;
     356                cbToRead = (uint32_t)(cbFile - (RTFOFF)offFile);
    254357            int rc = pThis->Core.pReader->pfnRead(pThis->Core.pReader, pbMem, cbToRead, offFile);
    255358            if (RT_FAILURE(rc))
     
    331434    if (uRva == NIL_RTLDRADDR || uRva > pThis->cbImage)
    332435    {
    333         if (offFile < 0)
     436        if (offFile < 0 || offFile >= UINT32_MAX)
    334437            return VERR_INVALID_PARAMETER;
    335         return rtldrPEReadPartFromFile(pThis, offFile, cbMem, ppvMem);
    336     }
    337     return rtldrPEReadPartByRva(pThis, pvBits, uRva, cbMem, ppvMem);
     438        return rtldrPEReadPartFromFile(pThis, (uint32_t)offFile, cbMem, ppvMem);
     439    }
     440    return rtldrPEReadPartByRva(pThis, pvBits, (uint32_t)uRva, cbMem, ppvMem);
    338441}
    339442
     
    549652                rc = VERR_BAD_EXE_FORMAT;
    550653            }
    551             pFirstThunk->u1.Function = Value;
     654            pFirstThunk->u1.Function = (uint32_t)Value;
    552655            if (pFirstThunk->u1.Function != Value)
    553656            {
     
    664767        /* Some bound checking just to be sure it works... */
    665768        if ((uintptr_t)pbr - (uintptr_t)pBaseRelocs + pbr->SizeOfBlock > cbBaseRelocs)
    666             cRelocations = (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(uint16_t);
     769            cRelocations = (uint32_t)(  (((uintptr_t)pBaseRelocs + cbBaseRelocs) - (uintptr_t)pbr - sizeof(IMAGE_BASE_RELOCATION))
     770                                      / sizeof(uint16_t) );
    667771
    668772        /*
     
    692796            {
    693797                case IMAGE_REL_BASED_HIGHLOW:   /* 32-bit, add delta. */
    694                     *u.pu32 += uDelta;
     798                    *u.pu32 += (uint32_t)uDelta;
    695799                    break;
    696800                case IMAGE_REL_BASED_DIR64:     /* 64-bit, add delta. */
     
    717821                    pwoffFixup++;
    718822                    int32_t i32 = (uint32_t)(*u.pu16 << 16) | *pwoffFixup;
    719                     i32 += uDelta;
     823                    i32 += (uint32_t)uDelta;
    720824                    i32 += 0x8000; //??
    721825                    *u.pu16 = (uint16_t)(i32 >> 16);
     
    760864
    761865/** @copydoc RTLDROPS::pfnRelocate. */
    762 static int rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress, PFNRTLDRIMPORT pfnGetImport, void *pvUser)
     866static DECLCALLBACK(int) rtldrPERelocate(PRTLDRMODINTERNAL pMod, void *pvBits, RTUINTPTR NewBaseAddress, RTUINTPTR OldBaseAddress,
     867                                         PFNRTLDRIMPORT pfnGetImport, void *pvUser)
    763868{
    764869    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     
    9261031    if (RT_SUCCESS(rc))
    9271032    {
    928         uintptr_t  uNamePrev = 0;
     1033        uint32_t uNamePrev = 0;
    9291034        for (uint32_t uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
    9301035        {
     
    10631168    uint32_t   *paRVANames = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNames, uint32_t *);
    10641169    uint16_t   *paOrdinals = PE_RVA2TYPE(pvBits, pExpDir->AddressOfNameOrdinals, uint16_t *);
    1065     uintptr_t   uNamePrev = 0;
     1170    uint32_t    uNamePrev = 0;
    10661171    unsigned    cOrdinals = RT_MAX(pExpDir->NumberOfNames, pExpDir->NumberOfFunctions);
    10671172    for (unsigned uOrdinal = 0; uOrdinal < cOrdinals; uOrdinal++)
     
    10741179            const char *pszName = NULL;
    10751180            /* Search from previous + 1 to the end.  */
    1076             unsigned    uName = uNamePrev + 1;
     1181            uint32_t uName = uNamePrev + 1;
    10771182            while (uName < pExpDir->NumberOfNames)
    10781183            {
     
    11471252
    11481253    /*
     1254     * Allocate temporary memory for a path buffer (this code is also compiled
     1255     * and maybe even used in stack starved environments).
     1256     */
     1257    char *pszPath = (char *)RTMemTmpAlloc(RTPATH_MAX);
     1258    if (!pszPath)
     1259        return VERR_NO_TMP_MEMORY;
     1260
     1261    /*
    11491262     * Get the debug directory.
    11501263     */
     
    11561269                                     (void const **)&paDbgDir);
    11571270    if (RT_FAILURE(rcRet))
     1271    {
     1272        RTMemTmpFree(pszPath);
    11581273        return rcRet;
     1274    }
    11591275
    11601276    /*
     
    11701286
    11711287        void const     *pvPart = NULL;
    1172         char            szPath[RTPATH_MAX];
    11731288        RTLDRDBGINFO    DbgInfo;
    11741289        RT_ZERO(DbgInfo.u);
     
    11901305                DbgInfo.u.Cv.uMinorVer  = paDbgDir[i].MinorVersion;
    11911306                DbgInfo.u.Cv.uTimestamp = paDbgDir[i].TimeDateStamp;
    1192                 if (   paDbgDir[i].SizeOfData < sizeof(szPath)
     1307                if (   paDbgDir[i].SizeOfData < RTPATH_MAX
    11931308                    && paDbgDir[i].SizeOfData > 16
    11941309                    && (   DbgInfo.LinkAddress != NIL_RTLDRADDR
     
    12281343            case IMAGE_DEBUG_TYPE_MISC:
    12291344                DbgInfo.enmType = RTLDRDBGINFOTYPE_UNKNOWN;
    1230                 if (   paDbgDir[i].SizeOfData < sizeof(szPath)
     1345                if (   paDbgDir[i].SizeOfData < RTPATH_MAX
    12311346                    && paDbgDir[i].SizeOfData > RT_UOFFSETOF(IMAGE_DEBUG_MISC, Data))
    12321347                {
     
    12491364                            else
    12501365                            {
    1251                                 char *pszPath = szPath;
    12521366                                rc = RTUtf16ToUtf8Ex((PCRTUTF16)&pMisc->Data[0],
    12531367                                                     (pMisc->Length - RT_OFFSETOF(IMAGE_DEBUG_MISC, Data)) / sizeof(RTUTF16),
    1254                                                      &pszPath, sizeof(szPath), NULL);
     1368                                                     &pszPath, RTPATH_MAX, NULL);
    12551369                                if (RT_SUCCESS(rc))
    1256                                     DbgInfo.pszExtFile = szPath;
     1370                                    DbgInfo.pszExtFile = pszPath;
    12571371                                else
    12581372                                    rcRet = rc; /* continue without a filename. */
     
    12831397           it's probably the current ANSI/Windows code page for the process
    12841398           generating the image anyways.) */
    1285         if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != szPath)
    1286         {
    1287             char *pszPath = szPath;
     1399        if (DbgInfo.pszExtFile && DbgInfo.pszExtFile != pszPath)
     1400        {
    12881401            rc = RTLatin1ToUtf8Ex(DbgInfo.pszExtFile,
    12891402                                  paDbgDir[i].SizeOfData - ((uintptr_t)DbgInfo.pszExtFile - (uintptr_t)pvBits),
    1290                                   &pszPath, sizeof(szPath), NULL);
     1403                                  &pszPath, RTPATH_MAX, NULL);
    12911404            if (RT_FAILURE(rc))
    12921405            {
     
    12961409        }
    12971410        if (DbgInfo.pszExtFile)
    1298             RTPathChangeToUnixSlashes(szPath, true /*fForce*/);
     1411            RTPathChangeToUnixSlashes(pszPath, true /*fForce*/);
    12991412
    13001413        rc = pfnCallback(pMod, &DbgInfo, pvUser);
     
    13081421
    13091422    rtldrPEFreePart(pModPe, pvBits, paDbgDir);
     1423    RTMemTmpFree(pszPath);
    13101424    return rcRet;
    13111425}
     
    14911605
    14921606/** @interface_method_impl{RTLDROPS,pfnQueryProp} */
    1493 static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf)
     1607static DECLCALLBACK(int) rtldrPE_QueryProp(PRTLDRMODINTERNAL pMod, RTLDRPROP enmProp, void *pvBuf, size_t cbBuf, size_t *pcbRet)
    14941608{
    14951609    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     
    14971611    {
    14981612        case RTLDRPROP_TIMESTAMP_SECONDS:
     1613            Assert(*pcbRet == cbBuf);
    14991614            if (cbBuf == sizeof(int32_t))
    15001615                *(int32_t *)pvBuf = pModPe->uTimestamp;
     
    15021617                *(int64_t *)pvBuf = pModPe->uTimestamp;
    15031618            else
    1504                 return VERR_INVALID_PARAMETER;
     1619                AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     1620            break;
     1621
     1622        case RTLDRPROP_IS_SIGNED:
     1623            Assert(cbBuf == sizeof(bool));
     1624            Assert(*pcbRet == cbBuf);
     1625            *(bool *)pvBuf = pModPe->offPkcs7SignedData != 0;
     1626            break;
     1627
     1628        case RTLDRPROP_PKCS7_SIGNED_DATA:
     1629        {
     1630            if (pModPe->cbPkcs7SignedData == 0)
     1631                return VERR_NOT_FOUND;
     1632            Assert(pModPe->offPkcs7SignedData > pModPe->SecurityDir.VirtualAddress);
     1633
     1634            *pcbRet = pModPe->cbPkcs7SignedData;
     1635            if (cbBuf < pModPe->cbPkcs7SignedData)
     1636                return VERR_BUFFER_OVERFLOW;
     1637            return pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pvBuf, pModPe->cbPkcs7SignedData,
     1638                                                 pModPe->offPkcs7SignedData);
     1639        }
     1640
     1641        case RTLDRPROP_SIGNATURE_CHECKS_ENFORCED:
     1642            Assert(cbBuf == sizeof(bool));
     1643            Assert(*pcbRet == cbBuf);
     1644            *(bool *)pvBuf = pModPe->offPkcs7SignedData > 0
     1645                          && (pModPe->fDllCharacteristics & IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY);
    15051646            break;
    15061647
     
    15121653
    15131654
     1655
     1656/*
     1657 * Lots of Authenticode fun ahead.
     1658 */
     1659
     1660
     1661/**
     1662 * Initializes the hash context.
     1663 *
     1664 * @returns VINF_SUCCESS or VERR_NOT_SUPPORTED.
     1665 * @param   pHashCtx            The hash context union.
     1666 * @param   enmDigest           The hash type we're calculating..
     1667 */
     1668static int rtLdrPE_HashInit(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest)
     1669{
     1670    switch (enmDigest)
     1671    {
     1672        case RTDIGESTTYPE_SHA512:  RTSha512Init(&pHashCtx->Sha512); break;
     1673        case RTDIGESTTYPE_SHA256:  RTSha256Init(&pHashCtx->Sha256); break;
     1674        case RTDIGESTTYPE_SHA1:    RTSha1Init(&pHashCtx->Sha1); break;
     1675        case RTDIGESTTYPE_MD5:     RTMd5Init(&pHashCtx->Md5); break;
     1676        default:                   AssertFailedReturn(VERR_NOT_SUPPORTED);
     1677    }
     1678    return VINF_SUCCESS;
     1679}
     1680
     1681
     1682/**
     1683 * Updates the hash with more data.
     1684 *
     1685 * @param   pHashCtx            The hash context union.
     1686 * @param   enmDigest           The hash type we're calculating..
     1687 * @param   pvBuf               Pointer to a buffer with bytes to add to thash.
     1688 * @param   cbBuf               How many bytes to add from @a pvBuf.
     1689 */
     1690static void rtLdrPE_HashUpdate(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, void const *pvBuf, size_t cbBuf)
     1691{
     1692    switch (enmDigest)
     1693    {
     1694        case RTDIGESTTYPE_SHA512:  RTSha512Update(&pHashCtx->Sha512, pvBuf, cbBuf); break;
     1695        case RTDIGESTTYPE_SHA256:  RTSha256Update(&pHashCtx->Sha256, pvBuf, cbBuf); break;
     1696        case RTDIGESTTYPE_SHA1:    RTSha1Update(&pHashCtx->Sha1, pvBuf, cbBuf); break;
     1697        case RTDIGESTTYPE_MD5:     RTMd5Update(&pHashCtx->Md5, pvBuf, cbBuf); break;
     1698        default:                   AssertReleaseFailed();
     1699    }
     1700}
     1701
     1702
     1703/**
     1704 * Finalizes the hash calculations.
     1705 *
     1706 * @param   pHashCtx            The hash context union.
     1707 * @param   enmDigest           The hash type we're calculating..
     1708 * @param   pHashRes            The hash result union.
     1709 */
     1710static void rtLdrPE_HashFinalize(PRTLDRPEHASHCTXUNION pHashCtx, RTDIGESTTYPE enmDigest, PRTLDRPEHASHRESUNION pHashRes)
     1711{
     1712    switch (enmDigest)
     1713    {
     1714        case RTDIGESTTYPE_SHA512:  RTSha512Final(&pHashCtx->Sha512, pHashRes->abSha512); break;
     1715        case RTDIGESTTYPE_SHA256:  RTSha256Final(&pHashCtx->Sha256, pHashRes->abSha256); break;
     1716        case RTDIGESTTYPE_SHA1:    RTSha1Final(&pHashCtx->Sha1, pHashRes->abSha1); break;
     1717        case RTDIGESTTYPE_MD5:     RTMd5Final(pHashRes->abMd5, &pHashCtx->Md5); break;
     1718        default:                   AssertReleaseFailed();
     1719    }
     1720}
     1721
     1722
     1723/**
     1724 * Returns the digest size for the given digest type.
     1725 *
     1726 * @returns Size in bytes.
     1727 * @param   enmDigest           The hash type in question.
     1728 */
     1729static uint32_t rtLdrPE_HashGetHashSize(RTDIGESTTYPE enmDigest)
     1730{
     1731    switch (enmDigest)
     1732    {
     1733        case RTDIGESTTYPE_SHA512:  return RTSHA512_HASH_SIZE;
     1734        case RTDIGESTTYPE_SHA256:  return RTSHA256_HASH_SIZE;
     1735        case RTDIGESTTYPE_SHA1:    return RTSHA1_HASH_SIZE;
     1736        case RTDIGESTTYPE_MD5:     return RTMD5_HASH_SIZE;
     1737        default:                   AssertReleaseFailedReturn(0);
     1738    }
     1739}
     1740
     1741
     1742/**
     1743 * Calculate the special too watch out for when hashing the image.
     1744 *
     1745 * @returns IPRT status code.
     1746 * @param   pModPe              The PE module.
     1747 * @param   pPlaces             The structure where to store the special places.
     1748 * @param   pErrInfo            Optional error info.
     1749 */
     1750static int rtldrPe_CalcSpecialHashPlaces(PRTLDRMODPE pModPe, PRTLDRPEHASHSPECIALS pPlaces, PRTERRINFO pErrInfo)
     1751{
     1752    /*
     1753     * If we're here despite a missing signature, we need to get the file size.
     1754     */
     1755    pPlaces->cbToHash = pModPe->SecurityDir.VirtualAddress;
     1756    if (pPlaces->cbToHash == 0)
     1757    {
     1758        RTFOFF cbFile = pModPe->Core.pReader->pfnSize(pModPe->Core.pReader);
     1759        pPlaces->cbToHash = (uint32_t)cbFile;
     1760        if (pPlaces->cbToHash != (RTFOFF)cbFile)
     1761            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_FILE_LENGTH_ERROR, "File is too large: %RTfoff", cbFile);
     1762    }
     1763
     1764    /*
     1765     * Calculate the special places.
     1766     */
     1767    pPlaces->offCksum       = (uint32_t)pModPe->offNtHdrs
     1768                            + (pModPe->f64Bit
     1769                               ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.CheckSum)
     1770                               : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum));
     1771    pPlaces->cbCksum        = RT_SIZEOFMEMB(IMAGE_NT_HEADERS32, OptionalHeader.CheckSum);
     1772    pPlaces->offSecDir      = (uint32_t)pModPe->offNtHdrs
     1773                            + (pModPe->f64Bit
     1774                               ? RT_OFFSETOF(IMAGE_NT_HEADERS64, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY])
     1775                               : RT_OFFSETOF(IMAGE_NT_HEADERS32, OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]));
     1776    pPlaces->cbSecDir       = sizeof(IMAGE_DATA_DIRECTORY);
     1777    pPlaces->offEndSpecial  = pPlaces->offSecDir + pPlaces->cbSecDir;
     1778    return VINF_SUCCESS;
     1779}
     1780
     1781
     1782/**
     1783 * Calculates the whole image hash.
     1784 *
     1785 * The Authenticode_PE.docx version 1.0 explains how the hash is calculated,
     1786 * points 8 thru 14 are bogus.  If you study them a little carefully, it is
     1787 * clear that the algorithm will only work if the raw data for the section have
     1788 * no gaps between them or in front of them.  So, this elaborate section sorting
     1789 * by PointerToRawData and working them section by section could simply be
     1790 * replaced by one point:
     1791 *
     1792 *      8. Add all the file content between SizeOfHeaders and the
     1793 *         attribute certificate table to the hash.  Then finalize
     1794 *         the hash.
     1795 *
     1796 * Not sure if Microsoft is screwing with us on purpose here or whether they
     1797 * assigned some of this work to less talented engineers and tech writers.  I
     1798 * love fact that they say it's "simplified" and should yield the correct hash
     1799 * for "almost all" files.  Stupid, Stupid, Microsofties!!
     1800 *
     1801 * My simplified implementation that just hashes the entire file up to the
     1802 * signature or end of the file produces the same SHA1 values as "signtool
     1803 * verify /v" does both for edited executables with gaps between/before/after
     1804 * sections raw data and normal executables without any gaps.
     1805 *
     1806 * @returns IPRT status code.
     1807 * @param   pModPe      The PE module.
     1808 * @param   pvScratch   Scratch buffer.
     1809 * @param   cbScratch   Size of the scratch buffer.
     1810 * @param   enmDigest   The hash digest type we're calculating.
     1811 * @param   pHashCtx    Hash context scratch area.
     1812 * @param   pHashRes    Hash result buffer.
     1813 * @param   pErrInfo    Optional error info buffer.
     1814 */
     1815static int rtldrPE_HashImageCommon(PRTLDRMODPE pModPe, void *pvScratch, uint32_t cbScratch, RTDIGESTTYPE enmDigest,
     1816                                   PRTLDRPEHASHCTXUNION pHashCtx, PRTLDRPEHASHRESUNION pHashRes, PRTERRINFO pErrInfo)
     1817{
     1818    int rc = rtLdrPE_HashInit(pHashCtx, enmDigest);
     1819    if (RT_FAILURE(rc))
     1820        return rc;
     1821
     1822    /*
     1823     * Calculate the special places.
     1824     */
     1825    RTLDRPEHASHSPECIALS SpecialPlaces;
     1826    rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
     1827    if (RT_FAILURE(rc))
     1828        return rc;
     1829
     1830    /*
     1831     * Work our way thru the image data.
     1832     */
     1833    uint32_t off = 0;
     1834    while (off < SpecialPlaces.cbToHash)
     1835    {
     1836        uint32_t cbRead = RT_MIN(SpecialPlaces.cbToHash - off, cbScratch);
     1837        uint8_t *pbCur  = (uint8_t *)pvScratch;
     1838        rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbRead, off);
     1839        if (RT_FAILURE(rc))
     1840            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH, "Hash read error at %#x: %Rrc (cbRead=%#zx)",
     1841                                 off, rc, cbRead);
     1842
     1843        if (off < SpecialPlaces.offEndSpecial)
     1844        {
     1845            if (off < SpecialPlaces.offCksum)
     1846            {
     1847                /* Hash everything up to the checksum. */
     1848                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbRead);
     1849                rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbChunk);
     1850                pbCur  += cbChunk;
     1851                cbRead -= cbChunk;
     1852                off    += cbChunk;
     1853            }
     1854
     1855            if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
     1856            {
     1857                /* Skip the checksum */
     1858                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbRead);
     1859                pbCur  += cbChunk;
     1860                cbRead -= cbChunk;
     1861                off    += cbChunk;
     1862            }
     1863
     1864            if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
     1865            {
     1866                /* Hash everything between the checksum and the data dir entry. */
     1867                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbRead);
     1868                rtLdrPE_HashUpdate(pHashCtx, enmDigest,  pbCur, cbChunk);
     1869                pbCur  += cbChunk;
     1870                cbRead -= cbChunk;
     1871                off    += cbChunk;
     1872            }
     1873
     1874            if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
     1875            {
     1876                /* Skip the security data directory entry. */
     1877                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbRead);
     1878                pbCur  += cbChunk;
     1879                cbRead -= cbChunk;
     1880                off    += cbChunk;
     1881            }
     1882        }
     1883
     1884        rtLdrPE_HashUpdate(pHashCtx, enmDigest, pbCur, cbRead);
     1885
     1886        /* Advance */
     1887        off += cbRead;
     1888    }
     1889
     1890    /*
     1891     * If there isn't a signature, experiments with signtool indicates that we
     1892     * have to zero padd the file size until it's a multiple of 8.  (This is
     1893     * most likely to give 64-bit values in the certificate a natural alignment
     1894     * when memory mapped.)
     1895     */
     1896    if (   pModPe->SecurityDir.Size != SpecialPlaces.cbToHash
     1897        && SpecialPlaces.cbToHash != RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT))
     1898    {
     1899        static const uint8_t s_abZeros[WIN_CERTIFICATE_ALIGNMENT] = { 0,0,0,0, 0,0,0,0 };
     1900        rtLdrPE_HashUpdate(pHashCtx, enmDigest, s_abZeros,
     1901                           RT_ALIGN_32(SpecialPlaces.cbToHash, WIN_CERTIFICATE_ALIGNMENT) - SpecialPlaces.cbToHash);
     1902    }
     1903
     1904    /*
     1905     * Done. Finalize the hashes.
     1906     */
     1907    rtLdrPE_HashFinalize(pHashCtx, enmDigest, pHashRes);
     1908    return VINF_SUCCESS;
     1909}
     1910
     1911#ifndef IPRT_WITHOUT_LDR_VERIFY
     1912
     1913/**
     1914 * Verifies image preconditions not checked by the open validation code.
     1915 *
     1916 * @returns IPRT status code.
     1917 * @param   pModPe              The PE module.
     1918 * @param   pErrInfo            Optional error info buffer.
     1919 */
     1920static int rtldrPE_VerifySignatureImagePrecoditions(PRTLDRMODPE pModPe, PRTERRINFO pErrInfo)
     1921{
     1922    /*
     1923     * Validate the sections.  While doing so, track the amount of section raw
     1924     * section data in the file so we can use this to validate the signature
     1925     * table location later.
     1926     */
     1927    uint32_t offNext = pModPe->cbHeaders; /* same */
     1928    for (uint32_t i = 0; i < pModPe->cSections; i++)
     1929        if (pModPe->paSections[i].SizeOfRawData > 0)
     1930        {
     1931            uint64_t offEnd = (uint64_t)pModPe->paSections[i].PointerToRawData + pModPe->paSections[i].SizeOfRawData;
     1932            if (offEnd > offNext)
     1933            {
     1934                if (offEnd >= _2G)
     1935                    return RTErrInfoSetF(pErrInfo, VERR_LDRVI_SECTION_RAW_DATA_VALUES,
     1936                                         "Section %#u specifies file data after 2GB: PointerToRawData=%#x SizeOfRawData=%#x",
     1937                                         i, pModPe->paSections[i].PointerToRawData, pModPe->paSections[i].SizeOfRawData);
     1938                offNext = (uint32_t)offEnd;
     1939            }
     1940        }
     1941    uint32_t offEndOfSectionData = offNext;
     1942
     1943    /*
     1944     * Validate the signature.
     1945     */
     1946    if (!pModPe->SecurityDir.Size)
     1947        return RTErrInfoSet(pErrInfo, VERR_LDRVI_NOT_SIGNED, "Not signed.");
     1948
     1949    uint32_t const offSignature = pModPe->SecurityDir.VirtualAddress;
     1950    uint32_t const cbSignature  = pModPe->SecurityDir.Size;
     1951    if (   cbSignature  <= sizeof(WIN_CERTIFICATE)
     1952        || cbSignature  >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE
     1953        || offSignature >= _2G)
     1954        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1955                             "Invalid security data dir entry: cb=%#x off=%#x", cbSignature, offSignature);
     1956
     1957    if (offSignature < offEndOfSectionData)
     1958        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1959                             "Invalid security data dir entry offset: %#x offEndOfSectionData=%#x",
     1960                             offSignature, offEndOfSectionData);
     1961
     1962    if (RT_ALIGN_32(offSignature, WIN_CERTIFICATE_ALIGNMENT) != offSignature)
     1963        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1964                             "Misaligned security dir entry offset: %#x (alignment=%#x)",
     1965                             offSignature, WIN_CERTIFICATE_ALIGNMENT);
     1966
     1967
     1968    return VINF_SUCCESS;
     1969}
     1970
     1971
     1972/**
     1973 * Reads and checks the raw signature data.
     1974 *
     1975 * @returns IPRT status code.
     1976 * @param   pModPe              The PE module.
     1977 * @param   ppSignature         Where to return the pointer to the parsed
     1978 *                              signature data.  Pass to
     1979 *                              rtldrPE_VerifySignatureDestroy when done.
     1980 * @param   pErrInfo            Optional error info buffer.
     1981 */
     1982static int rtldrPE_VerifySignatureRead(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE *ppSignature, PRTERRINFO pErrInfo)
     1983{
     1984    *ppSignature = NULL;
     1985    AssertReturn(pModPe->SecurityDir.Size > 0, VERR_INTERNAL_ERROR_2);
     1986
     1987    /*
     1988     * Allocate memory for reading and parsing it.
     1989     */
     1990    if (pModPe->SecurityDir.Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
     1991        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_INVALID_SECURITY_DIR_ENTRY,
     1992                             "Signature directory is to large: %#x", pModPe->SecurityDir.Size);
     1993
     1994    PRTLDRPESIGNATURE pSignature = (PRTLDRPESIGNATURE)RTMemTmpAllocZ(sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
     1995    if (!pSignature)
     1996        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_NO_MEMORY_SIGNATURE, "Failed to allocate %zu bytes",
     1997                             sizeof(*pSignature) + 64 + pModPe->SecurityDir.Size);
     1998    pSignature->pRawData = RT_ALIGN_PT(pSignature + 1, 64, WIN_CERTIFICATE const *);
     1999
     2000
     2001    /*
     2002     * Read it.
     2003     */
     2004    int rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, (void *)pSignature->pRawData,
     2005                                           pModPe->SecurityDir.Size, pModPe->SecurityDir.VirtualAddress);
     2006    if (RT_SUCCESS(rc))
     2007    {
     2008        /*
     2009         * Check the table we've read in.
     2010         */
     2011        uint32_t               cbLeft = pModPe->SecurityDir.Size;
     2012        WIN_CERTIFICATE const *pEntry = pSignature->pRawData;
     2013        for (;;)
     2014        {
     2015            if (   cbLeft           < sizeof(*pEntry)
     2016                || pEntry->dwLength > cbLeft
     2017                || pEntry->dwLength < sizeof(*pEntry))
     2018                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_LENGTH,
     2019                                   "Bad WIN_CERTIFICATE length: %#x  (max %#x, signature=%u)",
     2020                                   pEntry->dwLength, cbLeft, 0);
     2021            else if (pEntry->wRevision != WIN_CERT_REVISION_2_0)
     2022                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_REVISION,
     2023                                   "Unsupported WIN_CERTIFICATE revision value: %#x (signature=%u)",
     2024                                   pEntry->wRevision, 0);
     2025            else if (pEntry->wCertificateType != WIN_CERT_TYPE_PKCS_SIGNED_DATA)
     2026                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_BAD_CERT_HDR_TYPE,
     2027                                   "Unsupported WIN_CERTIFICATE certificate type: %#x (signature=%u)",
     2028                                   pEntry->wCertificateType, 0);
     2029            else
     2030            {
     2031                /* advance */
     2032                uint32_t cbEntry = RT_ALIGN(pEntry->dwLength, WIN_CERTIFICATE_ALIGNMENT);
     2033                if (cbEntry >= cbLeft)
     2034                    break;
     2035                cbLeft -= cbEntry;
     2036                pEntry = (WIN_CERTIFICATE *)((uintptr_t)pEntry + cbEntry);
     2037
     2038                /* For now, only one entry is supported. */
     2039                rc = RTErrInfoSet(pErrInfo, VERR_LDRVI_BAD_CERT_MULTIPLE, "Multiple WIN_CERTIFICATE entries are not supported.");
     2040            }
     2041            break;
     2042        }
     2043        if (RT_SUCCESS(rc))
     2044        {
     2045            *ppSignature = pSignature;
     2046            return VINF_SUCCESS;
     2047        }
     2048    }
     2049    else
     2050        rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_SIGNATURE, "Signature read error: %Rrc", rc);
     2051    RTMemTmpFree(pSignature);
     2052    return rc;
     2053}
     2054
     2055
     2056/**
     2057 * Destroys the parsed signature.
     2058 *
     2059 * @param   pModPe              The PE module.
     2060 * @param   pSignature          The signature data to destroy.
     2061 */
     2062static void rtldrPE_VerifySignatureDestroy(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature)
     2063{
     2064    RTCrPkcs7ContentInfo_Delete(&pSignature->ContentInfo);
     2065    RTMemTmpFree(pSignature);
     2066}
     2067
     2068
     2069/**
     2070 * Decodes the raw signature.
     2071 *
     2072 * @returns IPRT status code.
     2073 * @param   pModPe              The PE module.
     2074 * @param   pSignature          The signature data.
     2075 * @param   pErrInfo            Optional error info buffer.
     2076 */
     2077static int rtldrPE_VerifySignatureDecode(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
     2078{
     2079    WIN_CERTIFICATE const  *pEntry = pSignature->pRawData;
     2080    AssertReturn(pEntry->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA, VERR_INTERNAL_ERROR_2);
     2081    AssertReturn(pEntry->wRevision        == WIN_CERT_REVISION_2_0, VERR_INTERNAL_ERROR_2);
     2082
     2083    RTASN1CURSORPRIMARY PrimaryCursor;
     2084    RTAsn1CursorInitPrimary(&PrimaryCursor,
     2085                            &pEntry->bCertificate[0],
     2086                            pEntry->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate),
     2087                            pErrInfo,
     2088                            &g_RTAsn1DefaultAllocator,
     2089                            0,
     2090                            "WinCert");
     2091
     2092    int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pSignature->ContentInfo, "CI");
     2093    if (RT_SUCCESS(rc))
     2094    {
     2095        if (RTCrPkcs7ContentInfo_IsSignedData(&pSignature->ContentInfo))
     2096        {
     2097            pSignature->pSignedData = pSignature->ContentInfo.u.pSignedData;
     2098
     2099            /*
     2100             * Decode the authenticode bits.
     2101             */
     2102            if (!strcmp(pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID))
     2103            {
     2104                pSignature->pIndData = pSignature->pSignedData->ContentInfo.u.pIndirectDataContent;
     2105                Assert(pSignature->pIndData);
     2106
     2107                /*
     2108                 * Check that things add up.
     2109                 */
     2110                if (RT_SUCCESS(rc))
     2111                    rc = RTCrPkcs7SignedData_CheckSanity(pSignature->pSignedData,
     2112                                                         RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE
     2113                                                         | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH
     2114                                                         | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT,
     2115                                                         pErrInfo, "SD");
     2116                if (RT_SUCCESS(rc))
     2117                    rc = RTCrSpcIndirectDataContent_CheckSanityEx(pSignature->pIndData,
     2118                                                                  pSignature->pSignedData,
     2119                                                                  RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH,
     2120                                                                  pErrInfo);
     2121                if (RT_SUCCESS(rc))
     2122                {
     2123                    PCRTCRX509ALGORITHMIDENTIFIER pDigestAlgorithm = &pSignature->pIndData->DigestInfo.DigestAlgorithm;
     2124                    pSignature->enmDigest = RTCrX509AlgorithmIdentifier_QueryDigestType(pDigestAlgorithm);
     2125                    AssertReturn(pSignature->enmDigest != RTDIGESTTYPE_INVALID, VERR_INTERNAL_ERROR_4); /* Checked above! */
     2126                }
     2127            }
     2128            else
     2129                rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_EXPECTED_INDIRECT_DATA_CONTENT_OID,
     2130                                   "Unknown pSignedData.ContentInfo.ContentType.szObjId value: %s (expected %s)",
     2131                                   pSignature->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID);
     2132        }
     2133    }
     2134    return rc;
     2135}
     2136
     2137
     2138static int rtldrPE_VerifyAllPageHashesV2(PRTLDRMODPE pModPe, PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib, RTDIGESTTYPE enmDigest,
     2139                                         void *pvScratch, size_t cbScratch, PRTERRINFO pErrInfo)
     2140{
     2141    AssertReturn(cbScratch >= _4K, VERR_INTERNAL_ERROR_3);
     2142
     2143    /*
     2144     * Calculate the special places.
     2145     */
     2146    RTLDRPEHASHSPECIALS SpecialPlaces;
     2147    int rc = rtldrPe_CalcSpecialHashPlaces(pModPe, &SpecialPlaces, pErrInfo);
     2148    if (RT_FAILURE(rc))
     2149        return rc;
     2150
     2151    uint32_t const cbHash = rtLdrPE_HashGetHashSize(enmDigest);
     2152    uint32_t const cPages = pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb / (cbHash + 4);
     2153    if (cPages * (cbHash + 4) != pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb)
     2154        return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_SIZE_OVERFLOW,
     2155                             "Page Hashes V2 size issue: cb=%#x cbHash=%#x",
     2156                             pAttrib->u.pPageHashesV2->RawData.Asn1Core.cb, cbHash);
     2157
     2158    /*
     2159     * Walk the table.
     2160     */
     2161    uint32_t const  cbScratchReadMax = cbScratch & ~(uint32_t)(_4K - 1);
     2162    uint32_t        cbScratchRead    = 0;
     2163    uint32_t        offScratchRead   = 0;
     2164
     2165    uint32_t        offPrev    = 0;
     2166    uint32_t        offSectEnd = pModPe->cbHeaders;
     2167    uint32_t        iSh        = UINT32_MAX;
     2168    uint8_t const  *pbHashTab  = pAttrib->u.pPageHashesV2->RawData.Asn1Core.uData.pu8;
     2169    for (uint32_t iPage = 0; iPage < cPages; iPage++)
     2170    {
     2171        /* Decode the page offset. */
     2172        uint32_t const offFile = RT_MAKE_U32_FROM_U8(pbHashTab[0], pbHashTab[1], pbHashTab[2], pbHashTab[3]);
     2173        if (offFile >= SpecialPlaces.cbToHash)
     2174        {
     2175            /* The last entry is zero. */
     2176            if (   offFile   == SpecialPlaces.cbToHash
     2177                && iPage + 1 == cPages
     2178                && ASMMemIsAll8(pbHashTab + 4, cbHash, 0) == NULL)
     2179                return VINF_SUCCESS;
     2180            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_TOO_LONG,
     2181                                 "Page hash entry #%u is beyond the signature table start: %#x, %#x",
     2182                                 iPage, offFile, SpecialPlaces.cbToHash);
     2183        }
     2184        if (offFile < offPrev)
     2185            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_TAB_NOT_STRICTLY_SORTED,
     2186                                 "Page hash table is not strictly sorted: entry #%u @%#x, previous @%#x\n",
     2187                                 iPage, offFile, offPrev);
     2188
     2189        /* Figure out how much to read and how much to zero.  Need keep track
     2190           of the on-disk section boundraries. */
     2191        if (offFile >= offSectEnd)
     2192        {
     2193            iSh++;
     2194            if (   iSh < pModPe->cSections
     2195                && offFile - pModPe->paSections[iSh].PointerToRawData < pModPe->paSections[iSh].SizeOfRawData)
     2196                offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
     2197            else
     2198            {
     2199                iSh = 0;
     2200                while (   iSh < pModPe->cSections
     2201                       && offFile - pModPe->paSections[iSh].PointerToRawData >= pModPe->paSections[iSh].SizeOfRawData)
     2202                    iSh++;
     2203                if (iSh < pModPe->cSections)
     2204                    offSectEnd = pModPe->paSections[iSh].PointerToRawData + pModPe->paSections[iSh].SizeOfRawData;
     2205                else
     2206                    return RTErrInfoSetF(pErrInfo, VERR_PAGE_HASH_TAB_HASHES_NON_SECTION_DATA,
     2207                                         "Page hash entry #%u isn't in any section: %#x", iPage, offFile);
     2208            }
     2209        }
     2210
     2211        uint32_t cbRead = _4K;
     2212        if (offFile + cbRead > offSectEnd)
     2213            cbRead = offSectEnd - offFile;
     2214
     2215        if (offFile + cbRead > SpecialPlaces.cbToHash)
     2216            cbRead = SpecialPlaces.cbToHash - offFile;
     2217
     2218        /* Did we get a cache hit? */
     2219        uint8_t *pbCur = (uint8_t *)pvScratch;
     2220        if (   offFile + cbRead <= offScratchRead + cbScratchRead
     2221            && offFile          >= offScratchRead)
     2222            pbCur += offFile - offScratchRead;
     2223        /* Missed, read more. */
     2224        else
     2225        {
     2226            offScratchRead = offFile;
     2227            cbScratchRead  = offSectEnd - offFile;
     2228            if (cbScratchRead > cbScratchReadMax)
     2229                cbScratchRead = cbScratchReadMax;
     2230            rc = pModPe->Core.pReader->pfnRead(pModPe->Core.pReader, pbCur, cbScratchRead, offScratchRead);
     2231            if (RT_FAILURE(rc))
     2232                return RTErrInfoSetF(pErrInfo, VERR_LDRVI_READ_ERROR_HASH,
     2233                                     "Page hash read error at %#x: %Rrc (cbScratchRead=%#zx)",
     2234                                     offScratchRead, rc, cbScratchRead);
     2235        }
     2236
     2237        /* Zero any additional bytes in the page. */
     2238        if (cbRead != _4K)
     2239            memset(pbCur + cbRead, 0, _4K - cbRead);
     2240
     2241        /*
     2242         * Hash it.
     2243         */
     2244        RTLDRPEHASHCTXUNION HashCtx;
     2245        rc = rtLdrPE_HashInit(&HashCtx, enmDigest);
     2246        AssertRCReturn(rc, rc);
     2247
     2248        /* Deal with special places. */
     2249        uint32_t       cbLeft = _4K;
     2250        if (offFile < SpecialPlaces.offEndSpecial)
     2251        {
     2252            uint32_t off = offFile;
     2253            if (off < SpecialPlaces.offCksum)
     2254            {
     2255                /* Hash everything up to the checksum. */
     2256                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum - off, cbLeft);
     2257                rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2258                pbCur  += cbChunk;
     2259                cbLeft -= cbChunk;
     2260                off    += cbChunk;
     2261            }
     2262
     2263            if (off < SpecialPlaces.offCksum + SpecialPlaces.cbCksum && off >= SpecialPlaces.offCksum)
     2264            {
     2265                /* Skip the checksum */
     2266                uint32_t cbChunk = RT_MIN(SpecialPlaces.offCksum + SpecialPlaces.cbCksum - off, cbLeft);
     2267                pbCur  += cbChunk;
     2268                cbLeft -= cbChunk;
     2269                off    += cbChunk;
     2270            }
     2271
     2272            if (off < SpecialPlaces.offSecDir && off >= SpecialPlaces.offCksum + SpecialPlaces.cbCksum)
     2273            {
     2274                /* Hash everything between the checksum and the data dir entry. */
     2275                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir - off, cbLeft);
     2276                rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbChunk);
     2277                pbCur  += cbChunk;
     2278                cbLeft -= cbChunk;
     2279                off    += cbChunk;
     2280            }
     2281
     2282            if (off < SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir && off >= SpecialPlaces.offSecDir)
     2283            {
     2284                /* Skip the security data directory entry. */
     2285                uint32_t cbChunk = RT_MIN(SpecialPlaces.offSecDir + SpecialPlaces.cbSecDir - off, cbLeft);
     2286                pbCur  += cbChunk;
     2287                cbLeft -= cbChunk;
     2288                off    += cbChunk;
     2289            }
     2290        }
     2291
     2292        rtLdrPE_HashUpdate(&HashCtx, enmDigest, pbCur, cbLeft);
     2293
     2294        /*
     2295         * Finish the hash calculation and compare the result.
     2296         */
     2297        RTLDRPEHASHRESUNION HashRes;
     2298        rtLdrPE_HashFinalize(&HashCtx, enmDigest, &HashRes);
     2299
     2300        pbHashTab += 4;
     2301        if (memcmp(pbHashTab, &HashRes, cbHash) != 0)
     2302            return RTErrInfoSetF(pErrInfo, VERR_LDRVI_PAGE_HASH_MISMATCH,
     2303                                 "Page hash v2 failed for page #%u, @%#x, %#x bytes: %.*Rhxs != %.*Rhxs",
     2304                                 iPage, offFile, cbRead, (size_t)cbHash, pbHashTab, (size_t)cbHash, &HashRes);
     2305        pbHashTab += cbHash;
     2306        offPrev = offFile;
     2307    }
     2308
     2309    return VINF_SUCCESS;
     2310}
     2311
     2312
     2313/**
     2314 * Validates the image hash, including page hashes if present.
     2315 *
     2316 * @returns IPRT status code.
     2317 * @param   pModPe              The PE module.
     2318 * @param   pSignature          The decoded signature data.
     2319 * @param   pErrInfo            Optional error info buffer.
     2320 */
     2321static int rtldrPE_VerifySignatureValidateHash(PRTLDRMODPE pModPe, PRTLDRPESIGNATURE pSignature, PRTERRINFO pErrInfo)
     2322{
     2323    AssertReturn(pSignature->enmDigest > RTDIGESTTYPE_INVALID && pSignature->enmDigest < RTDIGESTTYPE_END, VERR_INTERNAL_ERROR_4);
     2324    AssertPtrReturn(pSignature->pIndData, VERR_INTERNAL_ERROR_5);
     2325    AssertReturn(RTASN1CORE_IS_PRESENT(&pSignature->pIndData->DigestInfo.Digest.Asn1Core), VERR_INTERNAL_ERROR_5);
     2326    AssertPtrReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, VERR_INTERNAL_ERROR_5);
     2327
     2328    uint32_t const cbHash = rtLdrPE_HashGetHashSize(pSignature->enmDigest);
     2329    AssertReturn(pSignature->pIndData->DigestInfo.Digest.Asn1Core.cb == cbHash, VERR_INTERNAL_ERROR_5);
     2330
     2331    /*
     2332     * Allocate a temporary memory buffer.
     2333     */
     2334#ifdef IN_RING0
     2335    uint32_t    cbScratch = _256K;
     2336#else
     2337    uint32_t    cbScratch = _1M;
     2338#endif
     2339    void       *pvScratch = RTMemTmpAlloc(cbScratch);
     2340    if (!pvScratch)
     2341    {
     2342        cbScratch = _4K;
     2343        pvScratch = RTMemTmpAlloc(cbScratch);
     2344        if (!pvScratch)
     2345            return RTErrInfoSet(pErrInfo, VERR_NO_TMP_MEMORY, "Failed to allocate 4KB of scratch space for hashing image.");
     2346    }
     2347
     2348    /*
     2349     * Calculate and compare the full image hash.
     2350     */
     2351    int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, pSignature->enmDigest,
     2352                                     &pSignature->HashCtx, &pSignature->HashRes, pErrInfo);
     2353    if (RT_SUCCESS(rc))
     2354    {
     2355        if (!memcmp(&pSignature->HashRes, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv, cbHash))
     2356        {
     2357            /*
     2358             * Compare the page hashes if present.
     2359             */
     2360            PCRTCRSPCSERIALIZEDOBJECTATTRIBUTE pAttrib = RTCrSpcIndirectDataContent_GetPeImageHashesV2(pSignature->pIndData);
     2361            if (pAttrib)
     2362                rc = rtldrPE_VerifyAllPageHashesV2(pModPe, pAttrib, pSignature->enmDigest, pvScratch, cbScratch, pErrInfo);
     2363
     2364            return rc;
     2365        }
     2366        rc = RTErrInfoSetF(pErrInfo, VERR_LDRVI_IMAGE_HASH_MISMATCH,
     2367                           "Full image signature mismatch: %.*Rhxs, expected %.*Rhxs",
     2368                           cbHash, &pSignature->HashRes,
     2369                           cbHash, pSignature->pIndData->DigestInfo.Digest.Asn1Core.uData.pv);
     2370    }
     2371
     2372    RTMemTmpFree(pvScratch);
     2373    return rc;
     2374}
     2375
     2376#endif /* !IPRT_WITHOUT_LDR_VERIFY */
     2377
     2378
     2379/** @interface_method_impl{RTLDROPS,pfnVerifySignature} */
     2380static DECLCALLBACK(int) rtldrPE_VerifySignature(PRTLDRMODINTERNAL pMod, PFNRTLDRVALIDATESIGNEDDATA pfnCallback, void *pvUser,
     2381                                                 PRTERRINFO pErrInfo)
     2382{
     2383#ifndef IPRT_WITHOUT_LDR_VERIFY
     2384    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     2385
     2386    int rc = rtldrPE_VerifySignatureImagePrecoditions(pModPe, pErrInfo);
     2387    if (RT_SUCCESS(rc))
     2388    {
     2389        PRTLDRPESIGNATURE pSignature = NULL;
     2390        rc = rtldrPE_VerifySignatureRead(pModPe, &pSignature, pErrInfo);
     2391        if (RT_SUCCESS(rc))
     2392        {
     2393            rc = rtldrPE_VerifySignatureDecode(pModPe, pSignature, pErrInfo);
     2394            if (RT_SUCCESS(rc))
     2395                rc = rtldrPE_VerifySignatureValidateHash(pModPe, pSignature, pErrInfo);
     2396            if (RT_SUCCESS(rc))
     2397            {
     2398                rc = pfnCallback(&pModPe->Core, RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA,
     2399                                 &pSignature->ContentInfo, sizeof(pSignature->ContentInfo),
     2400                                 pErrInfo, pvUser);
     2401            }
     2402            rtldrPE_VerifySignatureDestroy(pModPe, pSignature);
     2403        }
     2404    }
     2405    return rc;
     2406#else
     2407    return VERR_NOT_SUPPORTED;
     2408#endif
     2409}
     2410
     2411
     2412
     2413/**  @interface_method_impl{RTLDROPS,pfnHashImage}  */
     2414static DECLCALLBACK(int) rtldrPE_HashImage(PRTLDRMODINTERNAL pMod, RTDIGESTTYPE enmDigest, char *pszDigest, size_t cbDigest)
     2415{
     2416    PRTLDRMODPE pModPe = (PRTLDRMODPE)pMod;
     2417
     2418    /*
     2419     * Allocate a temporary memory buffer.
     2420     */
     2421    uint32_t    cbScratch = _16K;
     2422    void       *pvScratch = RTMemTmpAlloc(cbScratch);
     2423    if (!pvScratch)
     2424    {
     2425        cbScratch = _4K;
     2426        pvScratch = RTMemTmpAlloc(cbScratch);
     2427        if (!pvScratch)
     2428            return VERR_NO_TMP_MEMORY;
     2429    }
     2430
     2431    /*
     2432     * Do the hashing.
     2433     */
     2434    RTLDRPEHASHCTXUNION HashCtx;
     2435    RTLDRPEHASHRESUNION HashRes;
     2436    int rc = rtldrPE_HashImageCommon(pModPe, pvScratch, cbScratch, enmDigest, &HashCtx, &HashRes, NULL);
     2437    if (RT_SUCCESS(rc))
     2438    {
     2439        /*
     2440         * Format the digest into as human readable hash string.
     2441         */
     2442        switch (enmDigest)
     2443        {
     2444            case RTDIGESTTYPE_SHA512:  rc = RTSha512ToString(HashRes.abSha512, pszDigest, cbDigest); break;
     2445            case RTDIGESTTYPE_SHA256:  rc = RTSha256ToString(HashRes.abSha256, pszDigest, cbDigest); break;
     2446            case RTDIGESTTYPE_SHA1:    rc = RTSha1ToString(HashRes.abSha1, pszDigest, cbDigest); break;
     2447            case RTDIGESTTYPE_MD5:     rc = RTMd5ToString(HashRes.abMd5, pszDigest, cbDigest); break;
     2448            default:                   AssertFailedReturn(VERR_INTERNAL_ERROR_3);
     2449        }
     2450    }
     2451    return rc;
     2452}
     2453
     2454
    15142455/** @copydoc RTLDROPS::pfnDone */
    15152456static DECLCALLBACK(int) rtldrPEDone(PRTLDRMODINTERNAL pMod)
     
    15232464    return VINF_SUCCESS;
    15242465}
     2466
    15252467
    15262468/** @copydoc RTLDROPS::pfnClose */
     
    15662508        NULL,
    15672509        rtldrPE_QueryProp,
     2510        rtldrPE_VerifySignature,
     2511        rtldrPE_HashImage,
    15682512        42
    15692513    },
     
    15972541        NULL,
    15982542        rtldrPE_QueryProp,
     2543        rtldrPE_VerifySignature,
     2544        rtldrPE_HashImage,
    15992545        42
    16002546    },
     
    16602606     * volatile everywhere! Trying to prevent the compiler being a smarta$$ and reorder stuff.
    16612607     */
    1662     IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32 volatile *)pLoadCfg;
    1663     IMAGE_LOAD_CONFIG_DIRECTORY64 volatile *pLoadCfg64 = pLoadCfg;
    1664 
    1665     pLoadCfg64->SEHandlerCount             = pLoadCfg32->SEHandlerCount;
    1666     pLoadCfg64->SEHandlerTable             = pLoadCfg32->SEHandlerTable;
    1667     pLoadCfg64->SecurityCookie             = pLoadCfg32->SecurityCookie;
    1668     pLoadCfg64->EditList                   = pLoadCfg32->EditList;
    1669     pLoadCfg64->Reserved1                  = pLoadCfg32->Reserved1;
    1670     pLoadCfg64->CSDVersion                 = pLoadCfg32->CSDVersion;
    1671     pLoadCfg64->ProcessHeapFlags           = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
    1672     pLoadCfg64->ProcessAffinityMask        = pLoadCfg32->ProcessAffinityMask;
    1673     pLoadCfg64->VirtualMemoryThreshold     = pLoadCfg32->VirtualMemoryThreshold;
    1674     pLoadCfg64->MaximumAllocationSize      = pLoadCfg32->MaximumAllocationSize;
    1675     pLoadCfg64->LockPrefixTable            = pLoadCfg32->LockPrefixTable;
    1676     pLoadCfg64->DeCommitTotalFreeThreshold = pLoadCfg32->DeCommitTotalFreeThreshold;
    1677     uint32_t u32DeCommitFreeBlockThreshold = pLoadCfg32->DeCommitFreeBlockThreshold;
    1678     pLoadCfg64->DeCommitFreeBlockThreshold = u32DeCommitFreeBlockThreshold;
     2608    IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *pLoadCfg32 = (IMAGE_LOAD_CONFIG_DIRECTORY32_V3 volatile *)pLoadCfg;
     2609    IMAGE_LOAD_CONFIG_DIRECTORY64_V3 volatile *pLoadCfg64 = pLoadCfg;
     2610
     2611    pLoadCfg64->GuardFlags                  = pLoadCfg32->GuardFlags;
     2612    pLoadCfg64->GuardCFFunctionCount        = pLoadCfg32->GuardCFFunctionCount;
     2613    pLoadCfg64->GuardCFFunctionTable        = pLoadCfg32->GuardCFFunctionTable;
     2614    pLoadCfg64->Reserved2                   = pLoadCfg32->Reserved2;
     2615    pLoadCfg64->GuardCFCCheckFunctionPointer= pLoadCfg32->GuardCFCCheckFunctionPointer;
     2616    pLoadCfg64->SEHandlerCount              = pLoadCfg32->SEHandlerCount;
     2617    pLoadCfg64->SEHandlerTable              = pLoadCfg32->SEHandlerTable;
     2618    pLoadCfg64->SecurityCookie              = pLoadCfg32->SecurityCookie;
     2619    pLoadCfg64->EditList                    = pLoadCfg32->EditList;
     2620    pLoadCfg64->Reserved1                   = pLoadCfg32->Reserved1;
     2621    pLoadCfg64->CSDVersion                  = pLoadCfg32->CSDVersion;
     2622    pLoadCfg64->ProcessHeapFlags            = pLoadCfg32->ProcessHeapFlags; /* switched place with ProcessAffinityMask, but we're more than 16 byte off by now so it doesn't matter. */
     2623    pLoadCfg64->ProcessAffinityMask         = pLoadCfg32->ProcessAffinityMask;
     2624    pLoadCfg64->VirtualMemoryThreshold      = pLoadCfg32->VirtualMemoryThreshold;
     2625    pLoadCfg64->MaximumAllocationSize       = pLoadCfg32->MaximumAllocationSize;
     2626    pLoadCfg64->LockPrefixTable             = pLoadCfg32->LockPrefixTable;
     2627    pLoadCfg64->DeCommitTotalFreeThreshold  = pLoadCfg32->DeCommitTotalFreeThreshold;
     2628    uint32_t u32DeCommitFreeBlockThreshold  = pLoadCfg32->DeCommitFreeBlockThreshold;
     2629    pLoadCfg64->DeCommitFreeBlockThreshold  = u32DeCommitFreeBlockThreshold;
    16792630    /* the rest is equal. */
    16802631    Assert(     RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, DeCommitFreeBlockThreshold)
     
    17202671    /* This restriction needs to be implemented elsewhere. */
    17212672    if (   (pFileHdr->Characteristics & IMAGE_FILE_RELOCS_STRIPPED)
    1722         && !(fFlags & RTLDR_O_FOR_DEBUG))
     2673        && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    17232674    {
    17242675        Log(("rtldrPEOpen: %s: IMAGE_FILE_RELOCS_STRIPPED\n", pszLogName));
     
    18562807
    18572808            case IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT:  // 13
     2809                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2810                    break;
    18582811                Log(("rtldrPEOpen: %s: dir no. %d (DELAY_IMPORT) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    18592812                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    18702823                    return VERR_LDRPE_CERT_MALFORMED;
    18712824                }
    1872                 if (pDir->Size >= _1M)
     2825                if (pDir->Size >= RTLDRMODPE_MAX_SECURITY_DIR_SIZE)
    18732826                {
    18742827                    Log(("rtldrPEOpen: %s: Security directory is too large: %#x bytes\n", pszLogName, i, pDir->Size));
     
    18942847
    18952848            case IMAGE_DIRECTORY_ENTRY_TLS:           // 9
     2849                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2850                    break;
    18962851                Log(("rtldrPEOpen: %s: dir no. %d (TLS) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    18972852                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    18992854
    19002855            case IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR:// 14
     2856                if (fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION))
     2857                    break;
    19012858                Log(("rtldrPEOpen: %s: dir no. %d (COM_DESCRIPTOR) VirtualAddress=%#x Size=%#x is not supported!!!\n",
    19022859                     pszLogName, i, pDir->VirtualAddress, pDir->Size));
     
    19452902    for (unsigned cSHdrsLeft = cSections;  cSHdrsLeft > 0; cSHdrsLeft--, pSH++)
    19462903    {
    1947         const unsigned iSH = pSH - &paSections[0]; NOREF(iSH);
     2904        const unsigned iSH = (unsigned)(pSH - &paSections[0]); NOREF(iSH);
    19482905        Log3(("RTLdrPE: #%d '%-8.8s'  Characteristics: %08RX32\n"
    19492906              "RTLdrPE: VirtAddr: %08RX32  VirtSize: %08RX32\n"
     
    21103067
    21113068/**
    2112  * Validates the data of some selected data directories entries.
    2113  *
    2114  * This requires a valid section table and thus has to wait
    2115  * till after we've read and validated it.
     3069 * Validates the data of some selected data directories entries and remember
     3070 * important bits for later.
     3071 *
     3072 * This requires a valid section table and thus has to wait till after we've
     3073 * read and validated it.
    21163074 *
    21173075 * @returns iprt status code.
     
    21203078 * @param   fFlags      Loader flags, RTLDR_O_XXX.
    21213079 */
    2122 static int rtldrPEValidateDirectories(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
     3080static int rtldrPEValidateDirectoriesAndRememberStuff(PRTLDRMODPE pModPe, const IMAGE_OPTIONAL_HEADER64 *pOptHdr, uint32_t fFlags)
    21233081{
    21243082    const char *pszLogName = pModPe->Core.pReader->pfnLogName(pModPe->Core.pReader); NOREF(pszLogName);
     
    21363094    if (Dir.Size)
    21373095    {
    2138         const size_t cbExpect = pOptHdr->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC
    2139             ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
    2140             : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64);
    2141         if (    Dir.Size != cbExpect
    2142             && (    cbExpect == sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32)
    2143                 &&  Dir.Size != (uint32_t)RT_OFFSETOF(IMAGE_LOAD_CONFIG_DIRECTORY32, SEHandlerTable))
    2144            )
    2145         {
    2146             Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d.\n",
    2147                  pszLogName, Dir.Size, cbExpect));
     3096        const size_t cbExpectV3 = !pModPe->f64Bit
     3097                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V3)
     3098                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V3);
     3099        const size_t cbExpectV2 = !pModPe->f64Bit
     3100                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V2)
     3101                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2);
     3102        const size_t cbExpectV1 = !pModPe->f64Bit
     3103                                ? sizeof(IMAGE_LOAD_CONFIG_DIRECTORY32_V1)
     3104                                : sizeof(IMAGE_LOAD_CONFIG_DIRECTORY64_V2) /*No V1*/;
     3105
     3106        if (   Dir.Size != cbExpectV3
     3107            && Dir.Size != cbExpectV2
     3108            && Dir.Size != cbExpectV1)
     3109        {
     3110            Log(("rtldrPEOpen: %s: load cfg dir: unexpected dir size of %d bytes, expected %d, %d, or %d.\n",
     3111                 pszLogName, Dir.Size, cbExpectV3, cbExpectV2, cbExpectV1));
    21483112            return VERR_LDRPE_LOAD_CONFIG_SIZE;
    21493113        }
     
    21583122        rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
    21593123
    2160         if (u.Cfg64.Size != cbExpect)
    2161         {
    2162             Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
    2163                  pszLogName, u.Cfg64.Size, cbExpect));
    2164             return VERR_LDRPE_LOAD_CONFIG_SIZE;
    2165         }
    2166         if (u.Cfg64.LockPrefixTable)
     3124        if (u.Cfg64.Size != Dir.Size)
     3125        {
     3126            /* Kludge, seen ati shipping 32-bit DLLs and EXEs with Dir.Size=0x40
     3127               and Cfg64.Size=0x5c or 0x48.  Windows seems to deal with it, so
     3128               lets do so as well. */
     3129            if (   Dir.Size < u.Cfg64.Size
     3130                && (   u.Cfg64.Size == cbExpectV3
     3131                    || u.Cfg64.Size == cbExpectV2) )
     3132            {
     3133                Log(("rtldrPEOpen: %s: load cfg dir: Header (%d) and directory (%d) size mismatch, applying the ATI kludge\n",
     3134                     pszLogName, u.Cfg64.Size, Dir.Size));
     3135                Dir.Size = u.Cfg64.Size;
     3136                memset(&u.Cfg64, 0, sizeof(u.Cfg64));
     3137                rc = rtldrPEReadRVA(pModPe, &u.Cfg64, Dir.Size, Dir.VirtualAddress);
     3138                if (RT_FAILURE(rc))
     3139                    return rc;
     3140                rtldrPEConvert32BitLoadConfigTo64Bit(&u.Cfg64);
     3141            }
     3142            if (u.Cfg64.Size != Dir.Size)
     3143            {
     3144                Log(("rtldrPEOpen: %s: load cfg dir: unexpected header size of %d bytes, expected %d.\n",
     3145                     pszLogName, u.Cfg64.Size, Dir.Size));
     3146                return VERR_LDRPE_LOAD_CONFIG_SIZE;
     3147            }
     3148        }
     3149        if (u.Cfg64.LockPrefixTable && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    21673150        {
    21683151            Log(("rtldrPEOpen: %s: load cfg dir: lock prefix table at %RX64. We don't support lock prefix tables!\n",
     
    21793162        }
    21803163#endif
    2181         if (u.Cfg64.EditList)
     3164        if (u.Cfg64.EditList && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
    21823165        {
    21833166            Log(("rtldrPEOpen: %s: load cfg dir: EditList=%RX64 is unsupported!\n",
     
    21853168            return VERR_BAD_EXE_FORMAT;
    21863169        }
     3170        /** @todo GuardCFC? Possibly related to:
     3171         *         http://research.microsoft.com/pubs/69217/ccs05-cfi.pdf
     3172         * Not trusting something designed by bakas who don't know how to modify a
     3173         * structure without messing up its natural alignment. */
     3174        if (    (   u.Cfg64.GuardCFCCheckFunctionPointer
     3175                 || u.Cfg64.Reserved2
     3176                 || u.Cfg64.GuardCFFunctionTable
     3177                 || u.Cfg64.GuardCFFunctionCount
     3178                 || u.Cfg64.GuardFlags)
     3179            && !(fFlags & (RTLDR_O_FOR_DEBUG | RTLDR_O_FOR_VALIDATION)))
     3180        {
     3181            Log(("rtldrPEOpen: %s: load cfg dir: Guard stuff: %RX64,%RX64,%RX64,%RX64,%RX32!\n",
     3182                 pszLogName, u.Cfg64.GuardCFCCheckFunctionPointer, u.Cfg64.Reserved2,
     3183                 u.Cfg64.GuardCFFunctionTable, u.Cfg64.GuardCFFunctionCount, u.Cfg64.GuardFlags));
     3184            return VERR_BAD_EXE_FORMAT;
     3185        }
    21873186    }
    21883187
     
    21923191     */
    21933192    Dir = pOptHdr->DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
    2194     if (Dir.Size && !(fFlags & RTLDR_O_FOR_DEBUG))
     3193    if (Dir.Size)
    21953194    {
    21963195        PWIN_CERTIFICATE pFirst = (PWIN_CERTIFICATE)RTMemTmpAlloc(Dir.Size);
     
    22003199        if (RT_SUCCESS(rc))
    22013200        {
    2202             uint32_t         off  = 0;
    2203             PWIN_CERTIFICATE pCur = pFirst;
     3201            uint32_t off  = 0;
    22043202            do
    22053203            {
     3204                PWIN_CERTIFICATE pCur = (PWIN_CERTIFICATE)((uint8_t *)pFirst + off);
     3205
    22063206                /* validate the members. */
    2207                 uint32_t const cbCur = RT_ALIGN_32(pCur->dwLength, 8);
    2208                 if (   cbCur < sizeof(WIN_CERTIFICATE)
    2209                     || cbCur + off > RT_ALIGN_32(Dir.Size, 8))
     3207                if (   pCur->dwLength < sizeof(WIN_CERTIFICATE)
     3208                    || pCur->dwLength + off > Dir.Size)
    22103209                {
    22113210                    Log(("rtldrPEOpen: %s: cert at %#x/%#x: dwLength=%#x\n", pszLogName, off, Dir.Size, pCur->dwLength));
     
    22333232                }
    22343233
    2235                 /** @todo Rainy Day: Implement further verification using openssl. */
     3234                /* Remember the first signed data certificate. */
     3235                if (   pCur->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA
     3236                    && pModPe->offPkcs7SignedData == 0)
     3237                {
     3238                    pModPe->offPkcs7SignedData = Dir.VirtualAddress
     3239                                               + (uint32_t)((uintptr_t)&pCur->bCertificate[0] - (uintptr_t)pFirst);
     3240                    pModPe->cbPkcs7SignedData  = pCur->dwLength - RT_OFFSETOF(WIN_CERTIFICATE, bCertificate);
     3241                }
    22363242
    22373243                /* next */
    2238                 off += cbCur;
    2239                 pCur = (PWIN_CERTIFICATE)((uint8_t *)pCur + cbCur);
     3244                off += RT_ALIGN(pCur->dwLength, WIN_CERTIFICATE_ALIGNMENT);
    22403245            } while (off < Dir.Size);
    22413246        }
     
    22593264 * @param   offNtHdrs   The offset of the NT headers (where you find "PE\0\0").
    22603265 * @param   phLdrMod    Where to store the handle.
    2261  */
    2262 int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs, PRTLDRMOD phLdrMod)
     3266 * @param   pErrInfo    Where to return extended error information. Optional.
     3267 */
     3268int rtldrPEOpen(PRTLDRREADER pReader, uint32_t fFlags, RTLDRARCH enmArch, RTFOFF offNtHdrs,
     3269                PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo)
    22633270{
    22643271    /*
     
    23493356                pModPe->cbHeaders     = OptHdr.SizeOfHeaders;
    23503357                pModPe->uTimestamp    = FileHdr.TimeDateStamp;
     3358                pModPe->f64Bit        = FileHdr.SizeOfOptionalHeader == sizeof(OptHdr);
    23513359                pModPe->ImportDir     = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
    23523360                pModPe->RelocDir      = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];
    23533361                pModPe->ExportDir     = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
    23543362                pModPe->DebugDir      = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG];
     3363                pModPe->SecurityDir   = OptHdr.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
     3364                pModPe->fDllCharacteristics = OptHdr.DllCharacteristics;
    23553365
    23563366                /*
    23573367                 * Perform validation of some selected data directories which requires
    2358                  * inspection of the actual data.
     3368                 * inspection of the actual data.  This also saves some certificate
     3369                 * information.
    23593370                 */
    2360                 rc = rtldrPEValidateDirectories(pModPe, &OptHdr, fFlags);
     3371                rc = rtldrPEValidateDirectoriesAndRememberStuff(pModPe, &OptHdr, fFlags);
    23613372                if (RT_SUCCESS(rc))
    23623373                {
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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