| /** | |
| * This file has no copyright assigned and is placed in the Public Domain. | |
| * This file is part of the mingw-w64 runtime package. | |
| * No warranty is given; refer to the file DISCLAIMER.PD within this package. | |
| * | |
| * This file is derived from Microsoft implementation file delayhlp.cpp, which | |
| * is free for users to modify and derive. | |
| */ | |
| #ifndef WIN32_LEAN_AND_MEAN | |
| #define WIN32_LEAN_AND_MEAN | |
| #endif | |
| #include <windows.h> | |
| #include <delayimp.h> | |
| static size_t __strlen(const char *sz) | |
| { | |
| const char *szEnd = sz; | |
| while(*szEnd++ != 0) | |
| ; | |
| return szEnd - sz - 1; | |
| } | |
| static int __memcmp(const void *pv1,const void *pv2,size_t cb) | |
| { | |
| if(!cb) | |
| return 0; | |
| while(--cb && *(char *)pv1 == *(char *)pv2) { | |
| pv1 = ((char *)pv1) + 1; | |
| pv2 = ((char *)pv2) + 1; | |
| } | |
| return *((unsigned char *)pv1) - *((unsigned char *)pv2); | |
| } | |
| static void *__memcpy(void *pvDst,const void *pvSrc,size_t cb) | |
| { | |
| void *pvRet = pvDst; | |
| while(cb--) { | |
| *(char *)pvDst = *(char *)pvSrc; | |
| pvDst = ((char *)pvDst) + 1; | |
| pvSrc = ((char *)pvSrc) + 1; | |
| } | |
| return pvRet; | |
| } | |
| static unsigned IndexFromPImgThunkData(PCImgThunkData pitdCur,PCImgThunkData pitdBase) | |
| { | |
| return (unsigned) (pitdCur - pitdBase); | |
| } | |
| extern IMAGE_DOS_HEADER __ImageBase; | |
| #define PtrFromRVA(RVA) (((PBYTE)&__ImageBase) + (RVA)) | |
| typedef struct UnloadInfo *PUnloadInfo; | |
| typedef struct UnloadInfo { | |
| PUnloadInfo puiNext; | |
| PCImgDelayDescr pidd; | |
| } UnloadInfo; | |
| static unsigned CountOfImports(PCImgThunkData pitdBase) | |
| { | |
| unsigned cRet = 0; | |
| PCImgThunkData pitd = pitdBase; | |
| while(pitd->u1.Function) { | |
| pitd++; | |
| cRet++; | |
| } | |
| return cRet; | |
| } | |
| PUnloadInfo __puiHead = 0; | |
| static UnloadInfo *add_ULI(PCImgDelayDescr pidd_) | |
| { | |
| UnloadInfo *ret = (UnloadInfo *) LocalAlloc(LPTR,sizeof(UnloadInfo)); | |
| ret->pidd = pidd_; | |
| ret->puiNext = __puiHead; | |
| __puiHead = ret; | |
| return ret; | |
| } | |
| static void del_ULI(UnloadInfo *p) | |
| { | |
| if (p) { | |
| PUnloadInfo *ppui = &__puiHead; | |
| while(*ppui && *ppui!=p) { | |
| ppui = &((*ppui)->puiNext); | |
| } | |
| if(*ppui==p) *ppui = p->puiNext; | |
| LocalFree((void *)p); | |
| } | |
| } | |
| typedef struct InternalImgDelayDescr { | |
| DWORD grAttrs; | |
| LPCSTR szName; | |
| HMODULE *phmod; | |
| PImgThunkData pIAT; | |
| PCImgThunkData pINT; | |
| PCImgThunkData pBoundIAT; | |
| PCImgThunkData pUnloadIAT; | |
| DWORD dwTimeStamp; | |
| } InternalImgDelayDescr; | |
| typedef InternalImgDelayDescr *PIIDD; | |
| typedef const InternalImgDelayDescr *PCIIDD; | |
| static PIMAGE_NT_HEADERS WINAPI PinhFromImageBase(HMODULE hmod) | |
| { | |
| return (PIMAGE_NT_HEADERS) (((PBYTE)(hmod)) + ((PIMAGE_DOS_HEADER)(hmod))->e_lfanew); | |
| } | |
| static void WINAPI OverlayIAT(PImgThunkData pitdDst,PCImgThunkData pitdSrc) | |
| { | |
| __memcpy(pitdDst,pitdSrc,CountOfImports(pitdDst) * sizeof(IMAGE_THUNK_DATA)); | |
| } | |
| static DWORD WINAPI TimeStampOfImage(PIMAGE_NT_HEADERS pinh) | |
| { | |
| return pinh->FileHeader.TimeDateStamp; | |
| } | |
| static int WINAPI FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh,HMODULE hmod) | |
| { | |
| return ((UINT_PTR)(hmod)) == pinh->OptionalHeader.ImageBase; | |
| } | |
| #if(defined(_X86_) && !defined(__x86_64)) | |
| #undef InterlockedExchangePointer | |
| #define InterlockedExchangePointer(Target,Value) (PVOID)(LONG_PTR)InterlockedExchange((PLONG)(Target),(LONG)(LONG_PTR)(Value)) | |
| /*typedef unsigned long *PULONG_PTR;*/ | |
| #endif | |
| FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry); | |
| FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry) | |
| { | |
| InternalImgDelayDescr idd = { | |
| pidd->grAttrs,(LPCTSTR) PtrFromRVA(pidd->rvaDLLName),(HMODULE *) PtrFromRVA(pidd->rvaHmod), | |
| (PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaINT), | |
| (PCImgThunkData) PtrFromRVA(pidd->rvaBoundIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT), | |
| pidd->dwTimeStamp}; | |
| DelayLoadInfo dli = { | |
| sizeof(DelayLoadInfo),pidd,ppfnIATEntry,idd.szName,{ 0, { NULL } },0,0,0 | |
| }; | |
| HMODULE hmod; | |
| unsigned iIAT, iINT; | |
| PCImgThunkData pitd; | |
| FARPROC pfnRet; | |
| if(!(idd.grAttrs & dlattrRva)) { | |
| PDelayLoadInfo rgpdli[1] = { &dli}; | |
| RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_INVALID_PARAMETER),0,1,(PULONG_PTR)(rgpdli)); | |
| return 0; | |
| } | |
| hmod = *idd.phmod; | |
| iIAT = IndexFromPImgThunkData((PCImgThunkData)(ppfnIATEntry),idd.pIAT); | |
| iINT = iIAT; | |
| pitd = &(idd.pINT[iINT]); | |
| dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal); | |
| if(dli.dlp.fImportByName) | |
| dli.dlp.szProcName = | |
| (LPCSTR) | |
| ( | |
| ((PIMAGE_IMPORT_BY_NAME) PtrFromRVA( | |
| (RVA)((UINT_PTR)(pitd->u1.AddressOfData)) | |
| ) | |
| )->Name | |
| ); | |
| else dli.dlp.dwOrdinal = (DWORD)(IMAGE_ORDINAL(pitd->u1.Ordinal)); | |
| pfnRet = NULL; | |
| if(__pfnDliNotifyHook2) { | |
| pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing,&dli)); | |
| if(pfnRet!=NULL) goto HookBypass; | |
| } | |
| if(hmod==0) { | |
| if(__pfnDliNotifyHook2) | |
| hmod = (HMODULE) (((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary,&dli))); | |
| if(hmod==0) hmod = LoadLibraryA(dli.szDll); | |
| if(hmod==0) { | |
| dli.dwLastError = GetLastError(); | |
| if(__pfnDliFailureHook2) | |
| 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)); | |
| return dli.pfnCur; | |
| } | |
| } | |
| HMODULE hmodT = (HMODULE)(InterlockedExchangePointer((PVOID *) idd.phmod,(PVOID)(hmod))); | |
| if(hmodT!=hmod) { | |
| if(pidd->rvaUnloadIAT) add_ULI(pidd); | |
| } else FreeLibrary(hmod); | |
| } | |
| dli.hmodCur = hmod; | |
| if(__pfnDliNotifyHook2) pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress,&dli); | |
| if(pfnRet==0) { | |
| if(pidd->rvaBoundIAT && pidd->dwTimeStamp) { | |
| PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS) (PinhFromImageBase(hmod)); | |
| if(pinh->Signature==IMAGE_NT_SIGNATURE && | |
| TimeStampOfImage(pinh)==idd.dwTimeStamp && | |
| FLoadedAtPreferredAddress(pinh,hmod)) { | |
| pfnRet = (FARPROC) ((UINT_PTR)(idd.pBoundIAT[iIAT].u1.Function)); | |
| if(pfnRet!=0) goto SetEntryHookBypass; | |
| } | |
| } | |
| pfnRet = GetProcAddress(hmod,dli.dlp.szProcName); | |
| } | |
| if(!pfnRet) { | |
| dli.dwLastError = GetLastError(); | |
| if(__pfnDliFailureHook2) pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc,&dli); | |
| if(!pfnRet) { | |
| PDelayLoadInfo rgpdli[1] = { &dli}; | |
| RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND),0,1,(PULONG_PTR)(rgpdli)); | |
| pfnRet = dli.pfnCur; | |
| } | |
| } | |
| SetEntryHookBypass: | |
| *ppfnIATEntry = pfnRet; | |
| HookBypass: | |
| if(__pfnDliNotifyHook2) { | |
| dli.dwLastError = 0; | |
| dli.hmodCur = hmod; | |
| dli.pfnCur = pfnRet; | |
| (*__pfnDliNotifyHook2)(dliNoteEndProcessing,&dli); | |
| } | |
| return pfnRet; | |
| } | |
| WINBOOL WINAPI __FUnloadDelayLoadedDLL2(LPCSTR szDll) | |
| { | |
| WINBOOL fRet = FALSE; | |
| PUnloadInfo pui = __puiHead; | |
| for(pui = __puiHead;pui;pui = pui->puiNext) { | |
| LPCSTR szName = (LPCTSTR) PtrFromRVA(pui->pidd->rvaDLLName); | |
| size_t cbName = __strlen(szName); | |
| if(cbName==__strlen(szDll) && __memcmp(szDll,szName,cbName)==0) break; | |
| } | |
| if(pui && pui->pidd->rvaUnloadIAT) { | |
| PCImgDelayDescr pidd = pui->pidd; | |
| HMODULE *phmod = (HMODULE *) PtrFromRVA(pidd->rvaHmod); | |
| HMODULE hmod = *phmod; | |
| OverlayIAT((PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT)); | |
| FreeLibrary(hmod); | |
| *phmod = NULL; | |
| del_ULI((UnloadInfo *) pui); | |
| fRet = TRUE; | |
| } | |
| return fRet; | |
| } | |
| HRESULT WINAPI __HrLoadAllImportsForDll(LPCSTR szDll) | |
| { | |
| HRESULT hrRet = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND); | |
| PIMAGE_NT_HEADERS pinh = PinhFromImageBase((HMODULE) (&__ImageBase)); | |
| if(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size) { | |
| PCImgDelayDescr pidd; | |
| pidd = (PCImgDelayDescr) PtrFromRVA(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress); | |
| while(pidd->rvaDLLName) { | |
| LPCSTR szDllCur = (LPCSTR) PtrFromRVA(pidd->rvaDLLName); | |
| size_t cchDllCur = __strlen(szDllCur); | |
| if(cchDllCur==__strlen(szDll) && __memcmp(szDll,szDllCur,cchDllCur)==0) break; | |
| pidd++; | |
| } | |
| if(pidd->rvaDLLName) { | |
| FARPROC *ppfnIATEntry = (FARPROC *) PtrFromRVA(pidd->rvaIAT); | |
| size_t cpfnIATEntries = CountOfImports((PCImgThunkData) (ppfnIATEntry)); | |
| FARPROC *ppfnIATEntryMax = ppfnIATEntry + cpfnIATEntries; | |
| for(;ppfnIATEntry < ppfnIATEntryMax;ppfnIATEntry++) { | |
| __delayLoadHelper2(pidd,ppfnIATEntry); | |
| } | |
| hrRet = S_OK; | |
| } | |
| } | |
| return hrRet; | |
| } |