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; }
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; }