2025-04-27 07:49:33 -04:00

308 lines
8.0 KiB
C++

// Copyright (c) 1997-2001 Microsoft Corporation, All Rights Reserved
#define STRICT
#include <windows.h>
#pragma hdrstop
#include "delayImp.h"
#include <tchar.h>
extern "C"
PUnloadInfo __puiHead = 0;
struct ULI : public UnloadInfo {
ULI(PCImgDelayDescr pidd_) {
pidd = pidd_;
Link();
}
~ULI() {
Unlink();
}
void *
operator new(unsigned int cb) {
return ::LocalAlloc(LPTR, cb);
}
void
operator delete(void * pv) {
::LocalFree(pv);
}
void
Unlink() {
PUnloadInfo * ppui = &__puiHead;
while (*ppui && *ppui != this) {
ppui = &((*ppui)->puiNext);
}
if (*ppui == this) {
*ppui = puiNext;
}
}
void
Link() {
puiNext = __puiHead;
__puiHead = this;
}
};
static inline
PIMAGE_NT_HEADERS WINAPI
PinhFromImageBase(HMODULE);
static inline
DWORD WINAPI
TimeStampOfImage(PIMAGE_NT_HEADERS);
static inline
void WINAPI
OverlayIAT(PImgThunkData pitdDst, PCImgThunkData pitdSrc);
static inline
bool WINAPI
FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS, HMODULE);
extern "C"
FARPROC WINAPI
__delayLoadHelper(
PCImgDelayDescr pidd,
FARPROC * ppfnIATEntry
) {
// Set up some data we use for the hook procs but also useful for
// our own use
//
DelayLoadInfo dli = {
sizeof DelayLoadInfo,
pidd,
ppfnIATEntry,
pidd->szName,
{ 0 },
0,
0,
0
};
HMODULE hmod = *(pidd->phmod);
// 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.
//
unsigned iINT;
iINT = IndexFromPImgThunkData(PCImgThunkData(ppfnIATEntry), pidd->pIAT);
PCImgThunkData pitd = &((pidd->pINT)[iINT]);
if (dli.dlp.fImportByName = ((pitd->u1.Ordinal & IMAGE_ORDINAL_FLAG) == 0))
{
dli.dlp.szProcName = (LPCSTR)(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.
//
FARPROC pfnRet = NULL;
if (__pfnDliNotifyHook) {
if (pfnRet = ((*__pfnDliNotifyHook)(dliStartProcessing, &dli))) {
goto HookBypass;
}
}
if (hmod == 0) {
if (__pfnDliNotifyHook) {
hmod = HMODULE(((*__pfnDliNotifyHook)(dliNotePreLoadLibrary, &dli)));
}
#ifdef UNICODE
TCHAR tcName[MAX_PATH];
for (unsigned int i = 0; i < strlen(dli.szDll); i++)
{
TCHAR tc = dli.szDll[i];
tcName[i] = tc;
}
tcName[i] = '\0';
if (hmod == 0)
{
hmod = ::LoadLibrary(tcName);
}
#else
if (hmod == 0)
{
hmod = ::LoadLibrary(dli.szDll);
}
#endif
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)(dliFailLoadLib, &dli));
}
if (hmod == 0) {
PDelayLoadInfo pdli = &dli;
RaiseException(
VcppException(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
//
HMODULE hmodT = HMODULE(::InterlockedExchange(LPLONG(pidd->phmod), LONG(hmod)));
if (hmodT != hmod) {
// add lib to unload list if we have unload data
if (pidd->pUnloadIAT) {
ULI * puli = new ULI(pidd);
(void *)puli;
}
}
else {
::FreeLibrary(hmod);
}
}
// 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)(dliFailGetProc, &dli);
}
if (pfnRet == 0) {
PDelayLoadInfo pdli = &dli;
RaiseException(
VcppException(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;
}
#pragma intrinsic(strlen,memcmp,memcpy)
extern "C"
BOOL WINAPI
__FUnloadDelayLoadedDLL(LPCSTR szDll) {
BOOL fRet = FALSE;
PUnloadInfo pui = __puiHead;
for (pui = __puiHead; pui; pui = pui->puiNext) {
if (memcmp(szDll, pui->pidd->szName, strlen(pui->pidd->szName)) == 0) {
break;
}
}
if (pui && pui->pidd->pUnloadIAT) {
PCImgDelayDescr pidd = pui->pidd;
HMODULE hmod = *pidd->phmod;
OverlayIAT(pidd->pIAT, pidd->pUnloadIAT);
::FreeLibrary(hmod);
*pidd->phmod = NULL;
delete reinterpret_cast<ULI*> (pui);
fRet = TRUE;
}
return fRet;
}
static inline
PIMAGE_NT_HEADERS WINAPI
PinhFromImageBase(HMODULE hmod) {
return PIMAGE_NT_HEADERS(PCHAR(hmod) + PIMAGE_DOS_HEADER(hmod)->e_lfanew);
}
static inline
void WINAPI
OverlayIAT(PImgThunkData pitdDst, PCImgThunkData pitdSrc) {
memcpy(pitdDst, pitdSrc, CountOfImports(pitdDst) * sizeof IMAGE_THUNK_DATA);
}
static inline
DWORD WINAPI
TimeStampOfImage(PIMAGE_NT_HEADERS pinh) {
return pinh->FileHeader.TimeDateStamp;
}
static inline
bool WINAPI
FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh, HMODULE hmod) {
return DWORD(hmod) == pinh->OptionalHeader.ImageBase;
}