1 /**
2  * This file has no copyright assigned and is placed in the Public Domain.
3  * This file is part of the mingw-w64 runtime package.
4  * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5  *
6  * This file is derived from Microsoft implementation file delayhlp.cpp, which
7  * is free for users to modify and derive.
8  */
9 #ifndef WIN32_LEAN_AND_MEAN
10 #define WIN32_LEAN_AND_MEAN
11 #endif
12 #include <windows.h>
13 #include <delayimp.h>
14 
__strlen(const char * sz)15 static size_t __strlen(const char *sz)
16 {
17   const char *szEnd = sz;
18   while(*szEnd++ != 0)
19     ;
20   return szEnd - sz - 1;
21 }
22 
__memcmp(const void * pv1,const void * pv2,size_t cb)23 static int __memcmp(const void *pv1,const void *pv2,size_t cb)
24 {
25   if(!cb)
26     return 0;
27   while(--cb && *(char *)pv1 == *(char *)pv2) {
28     pv1 = ((char *)pv1) + 1;
29     pv2 = ((char *)pv2) + 1;
30   }
31   return *((unsigned char *)pv1) - *((unsigned char *)pv2);
32 }
33 
__memcpy(void * pvDst,const void * pvSrc,size_t cb)34 static void *__memcpy(void *pvDst,const void *pvSrc,size_t cb)
35 {
36   void *pvRet = pvDst;
37   while(cb--) {
38     *(char *)pvDst = *(char *)pvSrc;
39     pvDst = ((char *)pvDst) + 1;
40     pvSrc = ((char *)pvSrc) + 1;
41   }
42   return pvRet;
43 }
44 
IndexFromPImgThunkData(PCImgThunkData pitdCur,PCImgThunkData pitdBase)45 static unsigned IndexFromPImgThunkData(PCImgThunkData pitdCur,PCImgThunkData pitdBase)
46 {
47   return (unsigned) (pitdCur - pitdBase);
48 }
49 
50 #define __ImageBase __MINGW_LSYMBOL(_image_base__)
51 extern IMAGE_DOS_HEADER __ImageBase;
52 
53 #define PtrFromRVA(RVA)   (((PBYTE)&__ImageBase) + (RVA))
54 
55 typedef struct UnloadInfo *PUnloadInfo;
56 typedef struct UnloadInfo {
57   PUnloadInfo puiNext;
58   PCImgDelayDescr pidd;
59 } UnloadInfo;
60 
CountOfImports(PCImgThunkData pitdBase)61 static unsigned CountOfImports(PCImgThunkData pitdBase)
62 {
63   unsigned cRet = 0;
64   PCImgThunkData pitd = pitdBase;
65   while(pitd->u1.Function) {
66     pitd++;
67     cRet++;
68   }
69   return cRet;
70 }
71 
72 PUnloadInfo __puiHead = 0;
73 
add_ULI(PCImgDelayDescr pidd_)74 static UnloadInfo *add_ULI(PCImgDelayDescr pidd_)
75 {
76     UnloadInfo *ret = (UnloadInfo *) LocalAlloc(LPTR,sizeof(UnloadInfo));
77     ret->pidd = pidd_;
78     ret->puiNext = __puiHead;
79     __puiHead = ret;
80 	return ret;
81 }
82 
del_ULI(UnloadInfo * p)83 static void del_ULI(UnloadInfo *p)
84 {
85     if (p) {
86         PUnloadInfo *ppui = &__puiHead;
87         while(*ppui && *ppui!=p) {
88           ppui = &((*ppui)->puiNext);
89         }
90         if(*ppui==p) *ppui = p->puiNext;
91         LocalFree((void *)p);
92     }
93 }
94 
95 typedef struct InternalImgDelayDescr {
96   DWORD grAttrs;
97   LPCSTR szName;
98   HMODULE *phmod;
99   PImgThunkData pIAT;
100   PCImgThunkData pINT;
101   PCImgThunkData pBoundIAT;
102   PCImgThunkData pUnloadIAT;
103   DWORD dwTimeStamp;
104 } InternalImgDelayDescr;
105 
106 typedef InternalImgDelayDescr *PIIDD;
107 typedef const InternalImgDelayDescr *PCIIDD;
108 
PinhFromImageBase(HMODULE hmod)109 static PIMAGE_NT_HEADERS WINAPI PinhFromImageBase(HMODULE hmod)
110 {
111   return (PIMAGE_NT_HEADERS) (((PBYTE)(hmod)) + ((PIMAGE_DOS_HEADER)(hmod))->e_lfanew);
112 }
113 
OverlayIAT(PImgThunkData pitdDst,PCImgThunkData pitdSrc)114 static void WINAPI OverlayIAT(PImgThunkData pitdDst,PCImgThunkData pitdSrc)
115 {
116   __memcpy(pitdDst,pitdSrc,CountOfImports(pitdDst) * sizeof(IMAGE_THUNK_DATA));
117 }
118 
TimeStampOfImage(PIMAGE_NT_HEADERS pinh)119 static DWORD WINAPI TimeStampOfImage(PIMAGE_NT_HEADERS pinh)
120 {
121   return pinh->FileHeader.TimeDateStamp;
122 }
123 
FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh,HMODULE hmod)124 static int WINAPI FLoadedAtPreferredAddress(PIMAGE_NT_HEADERS pinh,HMODULE hmod)
125 {
126   return ((UINT_PTR)(hmod)) == pinh->OptionalHeader.ImageBase;
127 }
128 
129 #if(defined(_X86_) && !defined(__x86_64))
130 #undef InterlockedExchangePointer
131 #define InterlockedExchangePointer(Target,Value) (PVOID)(LONG_PTR)InterlockedExchange((PLONG)(Target),(LONG)(LONG_PTR)(Value))
132 /*typedef unsigned long *PULONG_PTR;*/
133 #endif
134 
135 FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry);
136 
__delayLoadHelper2(PCImgDelayDescr pidd,FARPROC * ppfnIATEntry)137 FARPROC WINAPI __delayLoadHelper2(PCImgDelayDescr pidd,FARPROC *ppfnIATEntry)
138 {
139   InternalImgDelayDescr idd = {
140     pidd->grAttrs,(LPCTSTR) PtrFromRVA(pidd->rvaDLLName),(HMODULE *) PtrFromRVA(pidd->rvaHmod),
141     (PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaINT),
142     (PCImgThunkData) PtrFromRVA(pidd->rvaBoundIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT),
143     pidd->dwTimeStamp};
144   DelayLoadInfo dli = {
145     sizeof(DelayLoadInfo),pidd,ppfnIATEntry,idd.szName,{ 0, { NULL } },0,0,0
146   };
147   HMODULE hmod;
148   unsigned iIAT, iINT;
149   PCImgThunkData pitd;
150   FARPROC pfnRet;
151 
152   if(!(idd.grAttrs & dlattrRva)) {
153     PDelayLoadInfo rgpdli[1] = { &dli};
154     RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_INVALID_PARAMETER),0,1,(PULONG_PTR)(rgpdli));
155     return 0;
156   }
157   hmod = *idd.phmod;
158   iIAT = IndexFromPImgThunkData((PCImgThunkData)(ppfnIATEntry),idd.pIAT);
159   iINT = iIAT;
160   pitd = &(idd.pINT[iINT]);
161 
162   dli.dlp.fImportByName = !IMAGE_SNAP_BY_ORDINAL(pitd->u1.Ordinal);
163   if(dli.dlp.fImportByName)
164     dli.dlp.szProcName =
165       (LPCSTR)
166       (
167         ((PIMAGE_IMPORT_BY_NAME) PtrFromRVA(
168         				     (RVA)((UINT_PTR)(pitd->u1.AddressOfData))
169         				   )
170         )->Name
171       );
172   else dli.dlp.dwOrdinal = (DWORD)(IMAGE_ORDINAL(pitd->u1.Ordinal));
173   pfnRet = NULL;
174   if(__pfnDliNotifyHook2) {
175     pfnRet = ((*__pfnDliNotifyHook2)(dliStartProcessing,&dli));
176     if(pfnRet!=NULL) goto HookBypass;
177   }
178   if(hmod==0) {
179     if(__pfnDliNotifyHook2)
180       hmod = (HMODULE) (((*__pfnDliNotifyHook2)(dliNotePreLoadLibrary,&dli)));
181     if(hmod==0) hmod = LoadLibrary(dli.szDll);
182     if(hmod==0) {
183       dli.dwLastError = GetLastError();
184       if(__pfnDliFailureHook2)
185         hmod = (HMODULE) ((*__pfnDliFailureHook2)(dliFailLoadLib,&dli));
186       if(hmod==0) {
187 	PDelayLoadInfo rgpdli[1] = { &dli};
188 	RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_MOD_NOT_FOUND),0,1,(PULONG_PTR)(rgpdli));
189 	return dli.pfnCur;
190       }
191     }
192     HMODULE hmodT = (HMODULE)(InterlockedExchangePointer((PVOID *) idd.phmod,(PVOID)(hmod)));
193     if(hmodT!=hmod) {
194       if(pidd->rvaUnloadIAT) add_ULI(pidd);
195     } else FreeLibrary(hmod);
196   }
197   dli.hmodCur = hmod;
198   if(__pfnDliNotifyHook2) pfnRet = (*__pfnDliNotifyHook2)(dliNotePreGetProcAddress,&dli);
199   if(pfnRet==0) {
200     if(pidd->rvaBoundIAT && pidd->dwTimeStamp) {
201       PIMAGE_NT_HEADERS pinh = (PIMAGE_NT_HEADERS) (PinhFromImageBase(hmod));
202       if(pinh->Signature==IMAGE_NT_SIGNATURE &&
203 	TimeStampOfImage(pinh)==idd.dwTimeStamp &&
204 	FLoadedAtPreferredAddress(pinh,hmod)) {
205 	  pfnRet = (FARPROC) ((UINT_PTR)(idd.pBoundIAT[iIAT].u1.Function));
206 	  if(pfnRet!=0) goto SetEntryHookBypass;
207       }
208     }
209     pfnRet = GetProcAddress(hmod,dli.dlp.szProcName);
210   }
211   if(!pfnRet) {
212     dli.dwLastError = GetLastError();
213     if(__pfnDliFailureHook2) pfnRet = (*__pfnDliFailureHook2)(dliFailGetProc,&dli);
214     if(!pfnRet) {
215       PDelayLoadInfo rgpdli[1] = { &dli};
216       RaiseException(VcppException(ERROR_SEVERITY_ERROR,ERROR_PROC_NOT_FOUND),0,1,(PULONG_PTR)(rgpdli));
217       pfnRet = dli.pfnCur;
218     }
219   }
220 SetEntryHookBypass:
221   *ppfnIATEntry = pfnRet;
222 HookBypass:
223   if(__pfnDliNotifyHook2) {
224     dli.dwLastError = 0;
225     dli.hmodCur = hmod;
226     dli.pfnCur = pfnRet;
227     (*__pfnDliNotifyHook2)(dliNoteEndProcessing,&dli);
228   }
229   return pfnRet;
230 }
231 
__FUnloadDelayLoadedDLL2(LPCSTR szDll)232 WINBOOL WINAPI __FUnloadDelayLoadedDLL2(LPCSTR szDll)
233 {
234   WINBOOL fRet = FALSE;
235   PUnloadInfo pui = __puiHead;
236 
237   for(pui = __puiHead;pui;pui = pui->puiNext) {
238     LPCSTR szName = (LPCTSTR) PtrFromRVA(pui->pidd->rvaDLLName);
239     size_t cbName = __strlen(szName);
240     if(cbName==__strlen(szDll) && __memcmp(szDll,szName,cbName)==0) break;
241   }
242   if(pui && pui->pidd->rvaUnloadIAT) {
243     PCImgDelayDescr pidd = pui->pidd;
244     HMODULE *phmod = (HMODULE *) PtrFromRVA(pidd->rvaHmod);
245     HMODULE hmod = *phmod;
246     OverlayIAT((PImgThunkData) PtrFromRVA(pidd->rvaIAT), (PCImgThunkData) PtrFromRVA(pidd->rvaUnloadIAT));
247     FreeLibrary(hmod);
248     *phmod = NULL;
249     del_ULI((UnloadInfo *) pui);
250     fRet = TRUE;
251   }
252   return fRet;
253 }
254 
__HrLoadAllImportsForDll(LPCSTR szDll)255 HRESULT WINAPI __HrLoadAllImportsForDll(LPCSTR szDll)
256 {
257   HRESULT hrRet = HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
258   PIMAGE_NT_HEADERS pinh = PinhFromImageBase((HMODULE) (&__ImageBase));
259   if(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].Size) {
260     PCImgDelayDescr pidd;
261     pidd = (PCImgDelayDescr) PtrFromRVA(pinh->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress);
262     while(pidd->rvaDLLName) {
263       LPCSTR szDllCur = (LPCSTR) PtrFromRVA(pidd->rvaDLLName);
264       size_t cchDllCur = __strlen(szDllCur);
265       if(cchDllCur==__strlen(szDll) && __memcmp(szDll,szDllCur,cchDllCur)==0) break;
266       pidd++;
267     }
268     if(pidd->rvaDLLName) {
269       FARPROC *ppfnIATEntry = (FARPROC *) PtrFromRVA(pidd->rvaIAT);
270       size_t cpfnIATEntries = CountOfImports((PCImgThunkData) (ppfnIATEntry));
271       FARPROC *ppfnIATEntryMax = ppfnIATEntry + cpfnIATEntries;
272       for(;ppfnIATEntry < ppfnIATEntryMax;ppfnIATEntry++) {
273         __delayLoadHelper2(pidd,ppfnIATEntry);
274       }
275       hrRet = S_OK;
276     }
277   }
278   return hrRet;
279 }
280