Hi,
I have recently played around a little with delay loading stuff. I have
written a __delayLoadHelper2 and the neccessary asm stubs to do delay
loading of a dll. It works and is implemented as documented on msdn /
Under The Hood.
The stubs are done by hand, but it shouldn't be too hard to write a tool
to autocreate them the same way as dlltool does it.
There will be no entry in the pe header, but that is optional anyway.
Are there any plans on how to handle that?
The best way would probably be, if dlltool could handle that, but ...
So I thought about a dlitool.exe that creates the stubs.
Any ideas?
For the ones interested: I have attached the sources. They allow to
delay import StrToIntA from shlwapi.dll
Timo
#include <windows.h>
#include "delayimp.h"
inline
unsigned
IndexFromPImgThunkData(PCImgThunkData pData, PCImgThunkData pBase)
{
return pData - pBase;
}
extern const IMAGE_DOS_HEADER _image_base__;
inline PVOID
PFromRva(RVA rva)
{
return (PVOID)(((ULONG_PTR)(rva)) + ((ULONG_PTR)&_image_base__));
}
/**** load helper ****/
FARPROC WINAPI
__delayLoadHelper2(PCImgDelayDescr pidd, PImgThunkData pIATEntry)
{
DelayLoadInfo dli;
int index;
PImgThunkData pIAT;
PImgThunkData pINT;
HMODULE *phMod;
FARPROC pProc;
pIAT = PFromRva(pidd->rvaIAT);
pINT = PFromRva(pidd->rvaINT);
phMod = PFromRva(pidd->rvaHmod);
index = IndexFromPImgThunkData(pIATEntry, pIAT);
dli.cb = sizeof(dli);
dli.pidd = pidd;
dli.ppfn = (FARPROC*)pIATEntry->u1.Function;
dli.szDll = PFromRva(pidd->rvaDLLName);
dli.dlp.fImportByName = !(pINT[index].u1.Ordinal & IMAGE_ORDINAL_FLAG);
if (dli.dlp.fImportByName)
{
/* u1.AdressOfData points to a IMAGE_IMPORT_BY_NAME struct */
PIMAGE_IMPORT_BY_NAME piibn = PFromRva((RVA)pINT[index].u1.AddressOfData);
dli.dlp.szProcName = (LPCSTR)&piibn->Name;
}
else
{
dli.dlp.dwOrdinal = pINT[index].u1.Ordinal & ~IMAGE_ORDINAL_FLAG;
}
dli.hmodCur = *phMod;
dli.pfnCur = (FARPROC)pIAT[index].u1.Function;
dli.dwLastError = GetLastError();
pProc = __pfnDliNotifyHook2(dliStartProcessing, &dli);
if (pProc)
{
pIAT[index].u1.Function = (DWORD)pProc;
return pProc;
}
if (dli.hmodCur == NULL)
{
dli.hmodCur = LoadLibraryA(dli.szDll);
if (!dli.hmodCur)
{
dli.dwLastError = GetLastError();
__pfnDliFailureHook2(dliFailLoadLib, &dli);
// if (ret)
// {
// }
// FIXME: raise exception;
return NULL;
}
*phMod = dli.hmodCur;
}
/* dli.dlp.szProcName might also contain the ordinal */
pProc = GetProcAddress(dli.hmodCur, dli.dlp.szProcName);
if (!pProc)
{
dli.dwLastError = GetLastError();
__pfnDliFailureHook2(dliFailGetProc, &dli);
// FIXME: handle return value & raise exception
return NULL;
}
pIAT[index].u1.Function = (DWORD)pProc;
return pProc;
}
/*** The default hooks ***/
FARPROC WINAPI
DefaultDliNotifyHook2(unsigned dliNotify, PDelayLoadInfo pdli)
{
return NULL;
}
FARPROC WINAPI
DefaultDliFailureHook2(unsigned dliNotify, PDelayLoadInfo pdli)
{
return NULL;
}
PfnDliHook __pfnDliNotifyHook2 = DefaultDliNotifyHook2;
PfnDliHook __pfnDliFailureHook2 = DefaultDliFailureHook2;
#ifndef _DELAYIMP_H_
#define _DELAYIMP_H_
typedef void *RVA;
typedef IMAGE_THUNK_DATA *PImgThunkData;
typedef const IMAGE_THUNK_DATA *PCImgThunkData;
enum
{
dlattrRva
};
/* Notification codes */
enum
{
dliStartProcessing,
dliNotePreLoadLibrary,
dliNotePreGetProcAddress,
dliFailLoadLib,
dliFailGetProc,
dliNoteEndProcessing,
};
typedef struct ImgDelayDescr
{
DWORD grAttrs;
RVA rvaDLLName;
RVA rvaHmod;
RVA rvaIAT;
RVA rvaINT;
RVA rvaBoundIAT;
RVA rvaUnloadIAT;
DWORD dwTimeStamp;
} ImgDelayDescr, *PImgDelayDescr;
typedef const ImgDelayDescr *PCImgDelayDescr;
typedef struct DelayLoadProc
{
BOOL fImportByName;
union
{
LPCSTR szProcName;
DWORD dwOrdinal;
};
} DelayLoadProc;
typedef struct DelayLoadInfo
{
DWORD cb;
PCImgDelayDescr pidd;
FARPROC *ppfn;
LPCSTR szDll;
DelayLoadProc dlp;
HMODULE hmodCur;
FARPROC pfnCur;
DWORD dwLastError;
} DelayLoadInfo, *PDelayLoadInfo;
typedef FARPROC (WINAPI *PfnDliHook)(unsigned, PDelayLoadInfo);
extern PfnDliHook __pfnDliNotifyHook2;
extern PfnDliHook __pfnDliFailureHook2;
#endif /* not _DELAYIMP_H_ */
.intel_syntax noprefix
.section .text
.global __tailMerge__shlwapi
__tailMerge__shlwapi:
push ecx
push edx
push eax
push offset __DELAY_IMPORT_DESCRIPTOR_SHLWAPI
call ___delayLoadHelper2@8
pop edx
pop ecx
jmp eax
# DELAY_IMPORT_DESCRIPTOR
.section .text$2
.global __DELAY_IMPORT_DESCRIPTOR_SHLWAPI
__DELAY_IMPORT_DESCRIPTOR_SHLWAPI:
.long 1 # grAttrs
.rva shlwapi_dll_iname # rvaDLLName
.rva shlwapi_dll_handle # rvaHmod
.rva shlwapi_dll_diat # rvaIAT
.rva shlwapi_dll_dint # rvaINT
.long 0 # rvaBoundIAT
.long 0 # rvaUnloadIAT
.long 0 # dwTimeStamp
.section .data
shlwapi_dll_handle:
.long 0
#Stuff for compatibility
.section .idata$5
.long 0
shlwapi_dll_diat:
.section .idata$4
.long 0
.section .idata$4
shlwapi_dll_dint:
.intel_syntax noprefix
.section .text
.global _StrToIntA@4
_StrToIntA@4:
jmp dword ptr [.idata$5]
__imp__load_StrToIntA@4:
mov eax, offset __imp__StrToIntA@4
jmp __tailMerge__shlwapi
# The INT
.section .idata$4
.rva .idata$6
# The IAT
.section .idata$5
__imp__StrToIntA@4:
.long __imp__load_StrToIntA@4
# The name
.section .idata$6
.byte 0x00, 0x00
.asciz "StrToIntA"
#.section .idata$7
# .rva __DELAY_IMPORT_DESCRIPTOR_SHLWAPI
.intel_syntax noprefix
# Terminate the INT
.section .idata$4
.long 0
# Terminate the IAT
.section .idata$5
.long 0
# The dll name
.section .idata$7
.global shlwapi_dll_iname
shlwapi_dll_iname:
.asciz "shlwapi.dll"