FARPROC WINAPI
__delayLoadHelper2(
    PCImgDelayDescr     pidd,
    FARPROC *           ppfnIATEntry
    ) {

    // Set up some data we use for the hook procs but also useful for
    // our own use
    //
    InternalImgDelayDescr   idd = {
        pidd->grAttrs,
        PFromRva<LPCSTR>(pidd->rvaDLLName),
        PFromRva<HMODULE*>(pidd->rvaHmod),
        PFromRva<PImgThunkData>(pidd->rvaIAT),
        PFromRva<PCImgThunkData>(pidd->rvaINT),
        PFromRva<PCImgThunkData>(pidd->rvaBoundIAT),
        PFromRva<PCImgThunkData>(pidd->rvaUnloadIAT),
        pidd->dwTimeStamp
        };

    DelayLoadInfo   dli = {
        sizeof DelayLoadInfo,
        pidd,
        ppfnIATEntry,
        idd.szName,
        { 0 },
        0,
        0,
        0
        };

    if (0 == (idd.grAttrs & dlattrRva)) {
        PDelayLoadInfo  rgpdli[1] = { &dli };

        RaiseException(
            VcppException(ERROR_SEVERITY_ERROR, ERROR_INVALID_PARAMETER),
            0,
            1,
            PULONG_PTR(rgpdli)
            );
        return 0;
        }

    HMODULE hmod = *idd.phmod;

    // Calculate the index for the IAT entry in the import address table
    // N.B. The INT entries are ordered the same as the IAT entries so
    // the calculation can be done on the IAT side.
    //
    const unsigned  iIAT = IndexFromPImgThunkData(PCImgThunkData(ppfnIATEntry), idd.pIAT);
    const unsigned  iINT = iIAT;

    PCImgThunkData  pitd = &(idd.pINT[iINT]);

    dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal);

    if (dli.dlp.fImportByName) {
        dli.dlp.szProcName = LPCSTR(PFromRva<PIMAGE_IMPORT_BY_NAME>(RVA(UINT_PTR(pitd->u1.AddressOfData)))->Name);
        }
    else {
        dli.dlp.dwOrdinal = DWORD(IMAGE_ORDINAL(pitd->u1.Ordinal));
        }

    // Call the initial hook.  If it exists and returns a function pointer,
    // abort the rest of the processing and just return it for the call.
    //
    FARPROC pfnRet = NULL;

    if (__pfnDliNotifyHook2) {
        pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing, &dli));

        if (pfnRet != NULL) {
            goto HookBypass;
            }
        }

    // Check to see if we need to try to load the library.
    //
    if (hmod == 0) {
        if (__pfnDliNotifyHook2) {
            hmod = HMODULE(((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary, &dli)));
            }
        if (hmod == 0) {
            hmod = ::LoadLibraryEx(dli.szDll, NULL, 0);
            }
        if (hmod == 0) {
            dli.dwLastError = ::GetLastError();
            if (__pfnDliFailureHook2) {
                // when the hook is called on LoadLibrary failure, it will
                // return 0 for failure and an hmod for the lib if it fixed
                // the problem.
                //
                hmod = HMODULE((*__pfnDliFailureHook2)(dliFailLoadLib, &dli));
                }

            if (hmod == 0) {
                PDelayLoadInfo  rgpdli[1] = { &dli };

                RaiseException(
                    VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND),
                    0,
                    1,
                    PULONG_PTR(rgpdli)
                    );
                
                // If we get to here, we blindly assume that the handler of the exception
                // has magically fixed everything up and left the function pointer in 
                // dli.pfnCur.
                //
                return dli.pfnCur;
                }
            }

        // Store the library handle.  If it is already there, we infer
        // that another thread got there first, and we need to do a
        // FreeLibrary() to reduce the refcount
        //
        HMODULE hmodT = HMODULE(InterlockedExchangePointer((PVOID *) idd.phmod, PVOID(hmod)));
        if (hmodT == hmod) {
            ::FreeLibrary(hmod);
            }
        }

    // Go for the procedure now.
    //
    dli.hmodCur = hmod;
    if (__pfnDliNotifyHook2) {
        pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress, &dli);
        }
    if (pfnRet == 0) {
        if (pidd->rvaBoundIAT && pidd->dwTimeStamp) {
            // bound imports exist...check the timestamp from the target image
            //
            PIMAGE_NT_HEADERS   pinh(PinhFromImageBase(hmod));

            if (pinh->Signature == IMAGE_NT_SIGNATURE &&
                TimeStampOfImage(pinh) == idd.dwTimeStamp &&
                FLoadedAtPreferredAddress(pinh, hmod)) {

                // Everything is good to go, if we have a decent address
                // in the bound IAT!
                //
                pfnRet = FARPROC(UINT_PTR(idd.pBoundIAT[iIAT].u1.Function));
                if (pfnRet != 0) {
                    goto SetEntryHookBypass;
                    }
                }
            }

        pfnRet = ::GetProcAddress(hmod, dli.dlp.szProcName);
        }

    if (pfnRet == 0) {
        dli.dwLastError = ::GetLastError();
        if (__pfnDliFailureHook2) {
            // when the hook is called on GetProcAddress failure, it will
            // return 0 on failure and a valid proc address on success
            //
            pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc, &dli);
            }
        if (pfnRet == 0) {
            PDelayLoadInfo  rgpdli[1] = { &dli };

            RaiseException(
                VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND),
                0,
                1,
                PULONG_PTR(rgpdli)
                );

            // If we get to here, we blindly assume that the handler of the exception
            // has magically fixed everything up and left the function pointer in 
            // dli.pfnCur.
            //
            pfnRet = dli.pfnCur;
            }
        }

SetEntryHookBypass:
    *ppfnIATEntry = pfnRet;

HookBypass:
    if (__pfnDliNotifyHook2) {
        dli.dwLastError = 0;
        dli.hmodCur = hmod;
        dli.pfnCur = pfnRet;
        (*__pfnDliNotifyHook2)(dliNoteEndProcessing, &dli);
        }
    return pfnRet;
    }
Beispiel #2
0
FARPROC WINAPI _EXPFUNC __delayLoadHelper(ImgDelayDescr *pidd, FARPROC *ppfnIATEntry)
{
    HMODULE                     hmod;
    unsigned                    iINT;
    FARPROC                     pfnRet;
    const IMAGE_THUNK_DATA *    pitd;

    // Set up some data we use for the hook procs but also useful for
    // our own use
    //
    DelayLoadInfo   dli;

    memset(&dli, 0, sizeof(dli));
    dli.cb = sizeof (DelayLoadInfo);
    dli.pidd = pidd;
    dli.ppfn = ppfnIATEntry;
    dli.szDll = pidd->szName;

    hmod = pidd->hmod;

    // Calculate the index for the name in the import name table.
    // N.B. it is ordered the same as the IAT entries so the calculation
    // comes from the IAT side.
    //
    iINT = IndexFromPImgThunkData((const IMAGE_THUNK_DATA *)ppfnIATEntry, pidd->pIAT);

    pitd = &((pidd->pINT)[iINT]);

    if ((dli.dlp.fImportByName = ((pitd->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0)) != 0)
    {
        dli.dlp.szProcName = (LPCSTR)((IMAGE_IMPORT_BY_NAME*)pitd->u1.AddressOfData)->Name;
    }
    else
    {
        dli.dlp.dwOrdinal = IMAGE_ORDINAL(pitd->u1.Ordinal);
    }

    // Call the initial hook.  If it exists and returns a function pointer,
    // abort the rest of the processing and just return it for the call.
    //
    pfnRet = NULL;

    if (__pfnDliNotifyHook)
    {
        if ((pfnRet = (*__pfnDliNotifyHook)(dliNoteStartProcessing, &dli)) != 0)
        {
            goto HookBypass;
        }
    }

    if (hmod == 0)
    {
        if (__pfnDliNotifyHook)
        {
            hmod = (HMODULE)(*__pfnDliNotifyHook)(dliNotePreLoadLibrary, &dli);
        }

        if (hmod == 0)
        {
            hmod = LoadLibrary(dli.szDll);
        }

        if (hmod == 0)
        {
            dli.dwLastError = GetLastError();
            if (__pfnDliFailureHook)
            {
                // when the hook is called on LoadLibrary failure, it will
                // return 0 for failure and an hmod for the lib if it fixed
                // the problem.
                //
                hmod = (HMODULE)(*__pfnDliFailureHook)(dliFailLoadLibrary, &dli);
            }

            if (hmod == 0)
            {
                DelayLoadInfo *  pdli = &dli;

                RaiseException(
                    BCPPException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND),
                    0,
                    1,
                    (PDWORD)&pdli
                );

                // If we get to here, we blindly assume that the handler of the exception
                // has magically fixed everything up and left the function pointer in
                // dli.pfnCur.
                //
                return dli.pfnCur;
            }
        }

        // Store the library handle.  If it is already there, we infer
        // that another thread got there first, and we need to do a
        // FreeLibrary() to reduce the refcount
        //
        EnterCriticalSection(&UnloadInfoCS);

        if (!pidd->hmod)
        {
            AddToUnloadList(pidd);
            pidd->hmod = hmod;
        }
        else
        {
            FreeLibrary(hmod);
            hmod = pidd->hmod;
        }

        LeaveCriticalSection(&UnloadInfoCS);
    }

    // Go for the procedure now.
    dli.hmodCur = hmod;

    if (__pfnDliNotifyHook)
    {
        pfnRet = (*__pfnDliNotifyHook)(dliNotePreGetProcAddress, &dli);
    }

    if (pfnRet == 0)
    {
        if (pidd->pBoundIAT && pidd->dwTimeStamp)
        {
            // bound imports exist...check the timestamp from the target image
            PIMAGE_NT_HEADERS   pinh = PinhFromImageBase(hmod);

            if (pinh->Signature == IMAGE_NT_SIGNATURE &&
                    TimeStampOfImage(pinh) == pidd->dwTimeStamp &&
                    FLoadedAtPreferredAddress(pinh, hmod))
            {

                OverlayIAT(pidd->pIAT, pidd->pBoundIAT);
                pfnRet = (FARPROC)pidd->pIAT[iINT].u1.Function;
                goto HookBypass;
            }
        }

        pfnRet = GetProcAddress(hmod, dli.dlp.szProcName);
    }

    if (pfnRet == 0)
    {
        dli.dwLastError = GetLastError();

        if (__pfnDliFailureHook)
        {
            // when the hook is called on GetProcAddress failure, it will
            // return 0 on failure and a valid proc address on success
            //
            pfnRet = (*__pfnDliFailureHook)(dliFailGetProcAddress, &dli);
        }

        if (pfnRet == 0)
        {
            DelayLoadInfo * pdli = &dli;

            RaiseException(
                BCPPException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND),
                0,
                1,
                (PDWORD)&pdli
            );

            // If we get to here, we blindly assume that the handler of the exception
            // has magically fixed everything up and left the function pointer in
            // dli.pfnCur.
            //
            pfnRet = dli.pfnCur;
        }
    }

    *ppfnIATEntry = pfnRet;

HookBypass:
    if (__pfnDliNotifyHook)
    {
        dli.dwLastError = 0;
        dli.hmodCur = hmod;
        dli.pfnCur = pfnRet;
        (*__pfnDliNotifyHook)(dliNoteEndProcessing, &dli);
    }

    return pfnRet;
}