BOOL CImage::Read()

in src/UndockedRegFreeWinRT/detours/image.cpp [1031:1340]


BOOL CImage::Read(HANDLE hFile)
{
    DWORD n;
    PBYTE pbData = NULL;
    DWORD cbData = 0;

    if (hFile == INVALID_HANDLE_VALUE) {
        SetLastError(ERROR_INVALID_HANDLE);
        return FALSE;
    }

    ///////////////////////////////////////////////////////// Create mapping.
    //
    m_nFileSize = GetFileSize(hFile, NULL);
    if (m_nFileSize == (DWORD)-1) {
        return FALSE;
    }

    m_hMap = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
    if (m_hMap == NULL) {
        return FALSE;
    }

    m_pMap = (PBYTE)MapViewOfFileEx(m_hMap, FILE_MAP_READ, 0, 0, 0, NULL);
    if (m_pMap == NULL) {
        return FALSE;
    }

    ////////////////////////////////////////////////////// Process DOS Header.
    //
    PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)m_pMap;
    if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
        SetLastError(ERROR_BAD_EXE_FORMAT);
        return FALSE;
    }
    m_nPeOffset = pDosHeader->e_lfanew;
    m_nPrePE = 0;
    m_cbPrePE = QuadAlign(pDosHeader->e_lfanew);

    if (m_nPeOffset > m_nFileSize ||
        m_nPeOffset + sizeof(m_NtHeader) > m_nFileSize) {

        SetLastError(ERROR_BAD_EXE_FORMAT);
        return FALSE;
    }

    CopyMemory(&m_DosHeader, m_pMap + m_nPrePE, sizeof(m_DosHeader));

    /////////////////////////////////////////////////////// Process PE Header.
    //
    CopyMemory(&m_NtHeader, m_pMap + m_nPeOffset, sizeof(m_NtHeader));
    if (m_NtHeader.Signature != IMAGE_NT_SIGNATURE) {
        SetLastError(ERROR_INVALID_EXE_SIGNATURE);
        return FALSE;
    }
    if (m_NtHeader.FileHeader.SizeOfOptionalHeader == 0) {
        SetLastError(ERROR_EXE_MARKED_INVALID);
        return FALSE;
    }
    m_nSectionsOffset = m_nPeOffset
        + sizeof(m_NtHeader.Signature)
        + sizeof(m_NtHeader.FileHeader)
        + m_NtHeader.FileHeader.SizeOfOptionalHeader;

    ///////////////////////////////////////////////// Process Section Headers.
    //
    if (m_NtHeader.FileHeader.NumberOfSections > ARRAYSIZE(m_SectionHeaders)) {
        SetLastError(ERROR_EXE_MARKED_INVALID);
        return FALSE;
    }
    CopyMemory(&m_SectionHeaders,
               m_pMap + m_nSectionsOffset,
               sizeof(m_SectionHeaders[0]) * m_NtHeader.FileHeader.NumberOfSections);

    /////////////////////////////////////////////////// Parse .detour Section.
    //
    DWORD rvaOriginalImageDirectory = 0;
    DWORD rvaDetourBeg = 0;
    DWORD rvaDetourEnd = 0;

    _Analysis_assume_(m_NtHeader.FileHeader.NumberOfSections <= ARRAYSIZE(m_SectionHeaders));

    for (n = 0; n < m_NtHeader.FileHeader.NumberOfSections; n++) {
        if (strcmp((PCHAR)m_SectionHeaders[n].Name, ".detour") == 0) {
            DETOUR_SECTION_HEADER dh;
            CopyMemory(&dh,
                       m_pMap + m_SectionHeaders[n].PointerToRawData,
                       sizeof(dh));

            rvaOriginalImageDirectory = dh.nOriginalImportVirtualAddress;
            if (dh.cbPrePE != 0) {
                m_nPrePE = m_SectionHeaders[n].PointerToRawData + sizeof(dh);
                m_cbPrePE = dh.cbPrePE;
            }
            rvaDetourBeg = m_SectionHeaders[n].VirtualAddress;
            rvaDetourEnd = rvaDetourBeg + m_SectionHeaders[n].SizeOfRawData;
        }
    }

    //////////////////////////////////////////////////////// Get Import Table.
    //
    DWORD rvaImageDirectory = m_NtHeader.OptionalHeader
        .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
    PIMAGE_IMPORT_DESCRIPTOR iidp
        = (PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(rvaImageDirectory);
    PIMAGE_IMPORT_DESCRIPTOR oidp
        = (PIMAGE_IMPORT_DESCRIPTOR)RvaToVa(rvaOriginalImageDirectory);

    if (oidp == NULL) {
        oidp = iidp;
    }
    if (iidp == NULL || oidp == NULL) {
        SetLastError(ERROR_EXE_MARKED_INVALID);
        return FALSE;
    }

    DWORD nFiles = 0;
    for (; iidp[nFiles].OriginalFirstThunk != 0 || iidp[nFiles].FirstThunk != 0; nFiles++) {
    }

    CImageImportFile **ppLastFile = &m_pImportFiles;
    m_pImportFiles = NULL;

    for (n = 0; n < nFiles; n++, iidp++) {
        ULONG_PTR rvaName = iidp->Name;
        PCHAR pszName = (PCHAR)RvaToVa(rvaName);
        if (pszName == NULL) {
            SetLastError(ERROR_EXE_MARKED_INVALID);
            goto fail;
        }

        CImageImportFile *pImportFile = new NOTHROW CImageImportFile;
        if (pImportFile == NULL) {
            SetLastError(ERROR_OUTOFMEMORY);
            goto fail;
        }

        *ppLastFile = pImportFile;
        ppLastFile = &pImportFile->m_pNextFile;
        m_nImportFiles++;

        pImportFile->m_pszName = DuplicateString(pszName);
        if (pImportFile->m_pszName == NULL) {
            goto fail;
        }

        pImportFile->m_rvaOriginalFirstThunk = iidp->OriginalFirstThunk;
        pImportFile->m_rvaFirstThunk = iidp->FirstThunk;
        pImportFile->m_nForwarderChain = iidp->ForwarderChain;
        pImportFile->m_pImportNames = NULL;
        pImportFile->m_nImportNames = 0;
        pImportFile->m_fByway = FALSE;

        if ((ULONG)iidp->FirstThunk >= rvaDetourBeg &&
            (ULONG)iidp->FirstThunk < rvaDetourEnd) {

            pImportFile->m_pszOrig = NULL;
            pImportFile->m_fByway = TRUE;
            continue;
        }

        rvaName = oidp->Name;
        pszName = (PCHAR)RvaToVa(rvaName);
        if (pszName == NULL) {
            SetLastError(ERROR_EXE_MARKED_INVALID);
            goto fail;
        }
        pImportFile->m_pszOrig = DuplicateString(pszName);
        if (pImportFile->m_pszOrig == NULL) {
            goto fail;
        }

        DWORD rvaThunk = iidp->OriginalFirstThunk;
        if( !rvaThunk ) {
            rvaThunk = iidp->FirstThunk;
        }
        PIMAGE_THUNK_DATA pAddrThunk = (PIMAGE_THUNK_DATA)RvaToVa(rvaThunk);
        rvaThunk = oidp->OriginalFirstThunk;
        if( !rvaThunk ) {
            rvaThunk = oidp->FirstThunk;
        }
        PIMAGE_THUNK_DATA pLookThunk = (PIMAGE_THUNK_DATA)RvaToVa(rvaThunk);

        DWORD nNames = 0;
        if (pAddrThunk) {
            for (; pAddrThunk[nNames].u1.Ordinal; nNames++) {
            }
        }

        if (pAddrThunk && nNames) {
            pImportFile->m_nImportNames = nNames;
            pImportFile->m_pImportNames = new NOTHROW CImageImportName [nNames];
            if (pImportFile->m_pImportNames == NULL) {
                SetLastError(ERROR_OUTOFMEMORY);
                goto fail;
            }

            CImageImportName *pImportName = &pImportFile->m_pImportNames[0];

            for (DWORD f = 0; f < nNames; f++, pImportName++) {
                pImportName->m_nOrig = 0;
                pImportName->m_nOrdinal = 0;
                pImportName->m_nHint = 0;
                pImportName->m_pszName = NULL;
                pImportName->m_pszOrig = NULL;

                rvaName = pAddrThunk[f].u1.Ordinal;
                if (rvaName & IMAGE_ORDINAL_FLAG) {
                    pImportName->m_nOrig = (ULONG)IMAGE_ORDINAL(rvaName);
                    pImportName->m_nOrdinal = pImportName->m_nOrig;
                }
                else {
                    PIMAGE_IMPORT_BY_NAME pName
                        = (PIMAGE_IMPORT_BY_NAME)RvaToVa(rvaName);
                    if (pName) {
                        pImportName->m_nHint = pName->Hint;
                        pImportName->m_pszName = DuplicateString((PCHAR)pName->Name);
                        if (pImportName->m_pszName == NULL) {
                            goto fail;
                        }
                    }

                    rvaName = pLookThunk[f].u1.Ordinal;
                    if (rvaName & IMAGE_ORDINAL_FLAG) {
                        pImportName->m_nOrig = (ULONG)IMAGE_ORDINAL(rvaName);
                        pImportName->m_nOrdinal = (ULONG)IMAGE_ORDINAL(rvaName);
                    }
                    else {
                        pName = (PIMAGE_IMPORT_BY_NAME)RvaToVa(rvaName);
                        if (pName) {
                            pImportName->m_pszOrig
                                = DuplicateString((PCHAR)pName->Name);
                            if (pImportName->m_pszOrig == NULL) {
                                goto fail;
                            }
                        }
                    }
                }
            }
        }
        oidp++;
    }

    ////////////////////////////////////////////////////////// Parse Sections.
    //
    m_nExtraOffset = 0;
    for (n = 0; n < m_NtHeader.FileHeader.NumberOfSections; n++) {
        m_nExtraOffset = Max(m_SectionHeaders[n].PointerToRawData +
                             m_SectionHeaders[n].SizeOfRawData,
                             m_nExtraOffset);

        if (strcmp((PCHAR)m_SectionHeaders[n].Name, ".detour") == 0) {
            DETOUR_SECTION_HEADER dh;
            CopyMemory(&dh,
                       m_pMap + m_SectionHeaders[n].PointerToRawData,
                       sizeof(dh));

            if (dh.nDataOffset == 0) {
                dh.nDataOffset = dh.cbHeaderSize;
            }

            cbData = dh.cbDataSize - dh.nDataOffset;
            pbData = (m_pMap +
                      m_SectionHeaders[n].PointerToRawData +
                      dh.nDataOffset);

            m_nExtraOffset = Max(m_SectionHeaders[n].PointerToRawData +
                                 m_SectionHeaders[n].SizeOfRawData,
                                 m_nExtraOffset);

            m_NtHeader.FileHeader.NumberOfSections--;

            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
                = dh.nOriginalImportVirtualAddress;
            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size
                = dh.nOriginalImportSize;

            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress
                = dh.nOriginalBoundImportVirtualAddress;
            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size
                = dh.nOriginalBoundImportSize;

            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress
                = dh.nOriginalIatVirtualAddress;
            m_NtHeader.OptionalHeader
                .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size
                = dh.nOriginalIatSize;

            m_NtHeader.OptionalHeader.CheckSum = 0;
            m_NtHeader.OptionalHeader.SizeOfImage
                = dh.nOriginalSizeOfImage;

            m_fHadDetourSection = TRUE;
        }
    }

    m_pImageData = new NOTHROW CImageData(pbData, cbData);
    if (m_pImageData == NULL) {
        SetLastError(ERROR_OUTOFMEMORY);
    }
    return TRUE;

fail:
    return FALSE;
}