[Rediff'd +Resent^2] Imagehlp - Imagebinding patches
Uwe Bonnes
bon at elektron.ikp.physik.tu-darmstadt.de
Wed Nov 2 10:26:36 CST 2005
These patches were sent and resent by Alex Ionescu <alex_at_relsoft.net>
summer 2004. I find no traces of an acknowledge, disgust or any other
discussion on the patch in our archives
Changelog:
dlls/imagehlp/access.c, dlls/imagehlp/modify.c:
Implemented ImageLoad, MapAndLoad, GetImageUnusedHeaderBytes,
BindImage
This lets PEDASM work with builtin imagehlp.
--
Uwe Bonnes bon at elektron.ikp.physik.tu-darmstadt.de
Institut fuer Kernphysik Schlossgartenstrasse 9 64289 Darmstadt
--------- Tel. 06151 162516 -------- Fax. 06151 164321 ----------
Index: wine/dlls/imagehlp/access.c
===================================================================
RCS file: /home/wine/wine/dlls/imagehlp/access.c,v
retrieving revision 1.21
diff -u -r1.21 access.c
--- wine/dlls/imagehlp/access.c 24 Mar 2005 21:01:38 -0000 1.21
+++ wine/dlls/imagehlp/access.c 2 Nov 2005 16:04:47 -0000
@@ -54,6 +54,8 @@
};
extern HANDLE IMAGEHLP_hHeap;
+BOOLEAN DllListInitialized;
+LIST_ENTRY ImageLoadListHead;
/***********************************************************************
* GetImageConfigInformation (IMAGEHLP.@)
@@ -76,11 +78,45 @@
PLOADED_IMAGE LoadedImage,
LPDWORD SizeUnusedHeaderBytes)
{
- FIXME("(%p, %p): stub\n",
- LoadedImage, SizeUnusedHeaderBytes
- );
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return 0;
+ DWORD FirstFreeByte;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader32 = NULL;
+ PIMAGE_NT_HEADERS NtHeaders;
+ ULONG i;
+
+ /* Read the NT Headers */
+ NtHeaders = LoadedImage->FileHeader;
+
+ /* Find the first free byte, which is after all the headers and sections */
+ FirstFreeByte = (ULONG_PTR)NtHeaders - (ULONG_PTR)LoadedImage->MappedAddress +
+ FIELD_OFFSET(IMAGE_NT_HEADERS, OptionalHeader) +
+ NtHeaders->FileHeader.SizeOfOptionalHeader +
+ NtHeaders->FileHeader.NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
+
+ /* Get the Optional Header */
+ OptionalHeader32 = &LoadedImage->FileHeader->OptionalHeader;
+
+ /* There is the possibilty that one of the Data Directories is in the PE Header
+ itself, so we'll need to find such a case and add it to our PE used space */
+ for ( i = 0; i<OptionalHeader32->NumberOfRvaAndSizes; i++ ) {
+
+ /* If the VA is less then the size of headers, then the data is inside the PE header */
+ if (OptionalHeader32->DataDirectory[i].VirtualAddress < OptionalHeader32->SizeOfHeaders) {
+
+ /* However, make sure it's not 0, which means it doesnt actually exist */
+ if (OptionalHeader32->DataDirectory[i].VirtualAddress >= FirstFreeByte) {
+
+ /* Our first empty byte is after this Directory Data then */
+ FirstFreeByte = OptionalHeader32->DataDirectory[i].VirtualAddress +
+ OptionalHeader32->DataDirectory[i].Size;
+ }
+ }
+ }
+
+ /* Return the unused Header Bytes */
+ *SizeUnusedHeaderBytes = OptionalHeader32->SizeOfHeaders - FirstFreeByte;
+
+ /* And return the first free byte*/
+ return FirstFreeByte;
}
/***********************************************************************
@@ -88,15 +124,58 @@
*/
PLOADED_IMAGE WINAPI ImageLoad(LPSTR DllName, LPSTR DllPath)
{
- PLOADED_IMAGE pLoadedImage;
+ PLIST_ENTRY Head,Next;
+ PLOADED_IMAGE LoadedImage;
+
+ /* Initialize the List Head */
+ if (!DllListInitialized) {
+ InitializeListHead(&ImageLoadListHead);
+ DllListInitialized = TRUE;
+ }
+
+ /* Move to the Next DLL */
+ Head = &ImageLoadListHead;
+ Next = Head->Flink;
+
+ TRACE("Trying to find library: %s in current ListHead \n", DllName);
+
+ /* Check if we already Loaded it */
+ while (Next != Head) {
+
+ /* Get the Loaded Image Structure */
+ LoadedImage = CONTAINING_RECORD(Next, LOADED_IMAGE, Links);
+ TRACE("Found: %s in current ListHead \n", LoadedImage->ModuleName);
+
+ /* Check if the Names Match */
+ if (!lstrcmpiA( DllName, LoadedImage->ModuleName )) {
+ TRACE("Found: %s\n the names match",DllName);
+ return LoadedImage;
+ }
+
+ /* Move to next Entry */
+ Next = Next->Flink;
+ TRACE("Moving to next List Entry\n");
+ }
+
+ /* Allocate memory for the Structure, and write the Module Name under */
+ LoadedImage = HeapAlloc(IMAGEHLP_hHeap, 0, sizeof(*LoadedImage) + lstrlenA(DllName) + 1);
- FIXME("(%s, %s): stub\n", DllName, DllPath);
+ /* Module Name will be after structure */
+ LoadedImage->ModuleName = (LPSTR)LoadedImage + 1;
- pLoadedImage = HeapAlloc(IMAGEHLP_hHeap, 0, sizeof(LOADED_IMAGE));
- if (pLoadedImage)
- pLoadedImage->FileHeader = HeapAlloc(IMAGEHLP_hHeap, 0, sizeof(IMAGE_NT_HEADERS));
+ /* Copy the Moduel Name */
+ lstrcpyA(LoadedImage->ModuleName, DllName);
- return pLoadedImage;
+ /* Now Load it and add it to our list*/
+ if (MapAndLoad(DllName, DllPath, LoadedImage, TRUE, TRUE)) {
+ InsertTailList(&ImageLoadListHead, &LoadedImage->Links);
+ return LoadedImage;
+ }
+
+ /* If we're here...there's been a failure */
+ HeapFree(IMAGEHLP_hHeap, 0, LoadedImage);
+ LoadedImage = NULL;
+ return LoadedImage;
}
/***********************************************************************
@@ -149,40 +228,62 @@
LPSTR pszImageName, LPSTR pszDllPath, PLOADED_IMAGE pLoadedImage,
BOOL bDotDll, BOOL bReadOnly)
{
- CHAR szFileName[MAX_PATH];
- HANDLE hFile = NULL;
HANDLE hFileMapping = NULL;
- HMODULE hModule = NULL;
- PIMAGE_NT_HEADERS pNtHeader = NULL;
+ PIMAGE_NT_HEADERS NtHeader = NULL;
+ ULONG Tried = 0;
+ CHAR Buffer[MAX_PATH];
+ LPSTR FilePart;
+ LPSTR FileToOpen;
+
- TRACE("(%s, %s, %p, %d, %d)\n", pszImageName, pszDllPath, pLoadedImage,
- bDotDll, bReadOnly);
+ /* So we can add the DLL Path later */
+ FileToOpen = pszImageName;
- /* PathCombine(&szFileName, pszDllPath, pszImageName); */
- /* PathRenameExtension(&szFileName, bDotDll?:"dll":"exe"); */
- /* FIXME: Check if the file already loaded (use IMAGEHLP_pFirstLoadedImage) */
- if(!(hFile = CreateFileA(
- szFileName, GENERIC_READ, 1, /* FIXME: FILE_SHARE_READ not defined */
- NULL, OPEN_EXISTING, 0, NULL)))
+TryAgain:
+ /* Get a handle to the file */
+ if ((pLoadedImage->hFile = CreateFileA (FileToOpen,
+ bReadOnly ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
+ bReadOnly ? FILE_SHARE_READ : FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL)) == INVALID_HANDLE_VALUE)
{
- SetLastError(ERROR_FILE_NOT_FOUND);
- goto Error;
+
+ /* It Failed, use the DLL Search Path then (make sure we haven't already) */
+ if (!Tried) {
+ Tried = SearchPathA(pszDllPath, pszImageName, bDotDll ? ".dll" : ".exe", MAX_PATH, Buffer, &FilePart);
+ if (Tried) {
+ FileToOpen = Buffer;
+ goto TryAgain;
+ }
+ }
+ /* Fail */
+ return FALSE;
}
- if(!(hFileMapping = CreateFileMappingA(
- hFile, NULL, PAGE_READONLY | SEC_COMMIT, 0, 0, NULL)))
+
+ /* Create the File Mapping */
+ if (!(hFileMapping = CreateFileMappingA (pLoadedImage->hFile,
+ NULL,
+ bReadOnly ? PAGE_READONLY : PAGE_READWRITE,
+ 0,
+ 0,
+ NULL)))
{
DWORD dwLastError = GetLastError();
WARN("CreateFileMapping: Error = %ld\n", dwLastError);
SetLastError(dwLastError);
goto Error;
}
- CloseHandle(hFile);
- hFile = NULL;
- if(!(hModule = (HMODULE) MapViewOfFile(
- hFileMapping, FILE_MAP_READ, 0, 0, 0)))
+ /* Get a pointer to the file */
+ if(!(pLoadedImage->MappedAddress = MapViewOfFile(hFileMapping,
+ bReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE,
+ 0,
+ 0,
+ 0)))
{
DWORD dwLastError = GetLastError();
WARN("MapViewOfFile: Error = %ld\n", dwLastError);
@@ -190,50 +291,48 @@
goto Error;
}
+
+ /* Close the handle to the map, we don't need it anymore */
CloseHandle(hFileMapping);
hFileMapping=NULL;
- pLoadedImage = HeapAlloc(IMAGEHLP_hHeap, 0, sizeof(LOADED_IMAGE));
- pNtHeader = RtlImageNtHeader(hModule);
+ /* Close the handle to the map, we don't need it anymore */
+ CloseHandle(hFileMapping);
+ hFileMapping=NULL;
- pLoadedImage->ModuleName = HeapAlloc(IMAGEHLP_hHeap, 0, strlen(pszDllPath)+1); /* FIXME: Correct? */
- strcpy( pLoadedImage->ModuleName, pszDllPath );
- pLoadedImage->hFile = hFile;
- pLoadedImage->MappedAddress = (PUCHAR) hModule;
- pLoadedImage->FileHeader = pNtHeader;
+ /* Get the Nt Header */
+ NtHeader = ImageNtHeader(pLoadedImage->MappedAddress);
+
+ /* Write data */
+ pLoadedImage->ModuleName = HeapAlloc(IMAGEHLP_hHeap, 0, lstrlenA(pszImageName) + 1);
+ lstrcpyA(pLoadedImage->ModuleName, pszImageName);
+ pLoadedImage->FileHeader = NtHeader;
pLoadedImage->Sections = (PIMAGE_SECTION_HEADER)
- ((LPBYTE) &pNtHeader->OptionalHeader +
- pNtHeader->FileHeader.SizeOfOptionalHeader);
- pLoadedImage->NumberOfSections =
- pNtHeader->FileHeader.NumberOfSections;
- pLoadedImage->SizeOfImage =
- pNtHeader->OptionalHeader.SizeOfImage;
- pLoadedImage->Characteristics =
- pNtHeader->FileHeader.Characteristics;
+ ((LPBYTE)&NtHeader->OptionalHeader +
+ NtHeader->FileHeader.SizeOfOptionalHeader);
+ pLoadedImage->NumberOfSections = NtHeader->FileHeader.NumberOfSections;
+ pLoadedImage->SizeOfImage = NtHeader->OptionalHeader.SizeOfImage;
+ pLoadedImage->Characteristics = NtHeader->FileHeader.Characteristics;
pLoadedImage->LastRvaSection = pLoadedImage->Sections;
-
pLoadedImage->fSystemImage = FALSE; /* FIXME */
pLoadedImage->fDOSImage = FALSE; /* FIXME */
- /* FIXME: Make thread safe */
- pLoadedImage->Links.Flink = NULL;
- pLoadedImage->Links.Blink = &IMAGEHLP_pLastLoadedImage->Links;
- if(IMAGEHLP_pLastLoadedImage)
- IMAGEHLP_pLastLoadedImage->Links.Flink = &pLoadedImage->Links;
- IMAGEHLP_pLastLoadedImage = pLoadedImage;
- if(!IMAGEHLP_pFirstLoadedImage)
- IMAGEHLP_pFirstLoadedImage = pLoadedImage;
+ /* Read only, so no sense in keeping the handle alive */
+ if (bReadOnly) CloseHandle(pLoadedImage->hFile);
+
+
+ /* Return Success */
return TRUE;
Error:
- if(hModule)
- UnmapViewOfFile((PVOID) hModule);
+ if(pLoadedImage->MappedAddress)
+ UnmapViewOfFile(pLoadedImage->MappedAddress);
if(hFileMapping)
CloseHandle(hFileMapping);
- if(hFile)
- CloseHandle(hFile);
+ if(pLoadedImage->hFile)
+ CloseHandle(pLoadedImage->hFile);
return FALSE;
}
Index: wine/dlls/imagehlp/modify.c
===================================================================
RCS file: /home/wine/wine/dlls/imagehlp/modify.c,v
retrieving revision 1.13
diff -u -r1.13 modify.c
--- wine/dlls/imagehlp/modify.c 21 Nov 2003 21:31:35 -0000 1.13
+++ wine/dlls/imagehlp/modify.c 2 Nov 2005 16:04:49 -0000
@@ -30,8 +30,669 @@
WINE_DEFAULT_DEBUG_CHANNEL(imagehlp);
+/* Internal Structures we use to keep track of the Bound Imports */
+typedef struct _BOUND_FORWARDER_REFS {
+ ULONG TimeDateStamp;
+ LPSTR ModuleName;
+} BOUND_FORWARDER_REFS, *PBOUND_FORWARDER_REFS;
+
+typedef struct _BOUND_IMPORT_DESCRIPTOR {
+ LPSTR ModuleName;
+ ULONG TimeDateStamp;
+ USHORT ForwaderReferences;
+ PBOUND_FORWARDER_REFS Forwarders;
+} BOUND_IMPORT_DESCRIPTOR, *PBOUND_IMPORT_DESCRIPTOR;
+
+CHAR BoundLibraries[4096];
+LPSTR BoundLibrariesPointer = BoundLibraries;
+PULONG BoundImportDescriptors;
+
static WORD CalcCheckSum(DWORD StartValue, LPVOID BaseAddress, DWORD WordCount);
+/*
+ * BindpCreateBoundImportDescriptor
+ *
+ * FUNCTION:
+ * Creates an Internal Structure for the Bound Library
+ *
+ * ARGUMENTS:
+ * LibraryName - Name of the Library
+ * Library - Loaded Library
+ * BoundImportDescriptor - Internal Bound Import Descriptor of Library
+ *
+ * RETURNS:
+ * PBOUND_IMPORT_DESCRIPTOR - Pointer to the Internal Bind Structure
+ */
+PBOUND_IMPORT_DESCRIPTOR
+WINAPI
+BindpCreateBoundImportDescriptor(
+ LPSTR LibraryName,
+ PLOADED_IMAGE Library,
+ PULONG BoundImportDescriptor
+ )
+{
+ PBOUND_IMPORT_DESCRIPTOR CurrentBoundImportDescriptor;
+
+ /* Load the First Descriptor */
+ CurrentBoundImportDescriptor = (PBOUND_IMPORT_DESCRIPTOR)BoundImportDescriptor;
+
+ /* Check if we've already bound this library */
+ while (CurrentBoundImportDescriptor->ModuleName) {
+ if (!lstrcmpiA(CurrentBoundImportDescriptor->ModuleName, LibraryName)) {
+ return CurrentBoundImportDescriptor;
+ }
+ CurrentBoundImportDescriptor++;
+ }
+
+ /* Save Library Name in Bound Libraries Buffer */
+ strcat((char *)BoundLibrariesPointer, LibraryName);
+
+ /* Set Data */
+ CurrentBoundImportDescriptor->ModuleName = BoundLibrariesPointer;
+ CurrentBoundImportDescriptor->TimeDateStamp = Library->FileHeader->FileHeader.TimeDateStamp;
+
+ /* Support for up to 32 Forwarded DLLs */
+ CurrentBoundImportDescriptor->Forwarders = GlobalAlloc(GMEM_ZEROINIT, 32* sizeof(BOUND_FORWARDER_REFS));
+
+ /* Next String */
+ BoundLibrariesPointer = BoundLibrariesPointer + strlen((char *)BoundLibrariesPointer) + 1;
+
+ return CurrentBoundImportDescriptor;
+}
+
+/*
+ * BindpAddBoundForwarder
+ *
+ * FUNCTION:
+ * Finds the pointer of the Forwarded function, and writes it into the Thunk,
+ * thus making the Thunk Bound.
+ *
+ * ARGUMENTS:
+ * BoundImportDescriptor - Internal Bound Import Descriptor of LoadedLibrary
+ * DllPath - DLL Search Path
+ * ForwarderString - Name of the Forwader String
+ *
+ * RETURNS:
+ * Pointer to the Forwaded Function.
+ */
+ULONG
+WINAPI
+BindpAddBoundForwarder(
+ PBOUND_IMPORT_DESCRIPTOR BoundImportDescriptor,
+ LPSTR DllPath,
+ PCHAR ForwarderString
+ )
+{
+ CHAR DllName[256];
+ PCHAR TempDllName;
+ PLOADED_IMAGE LoadedLibrary;
+ ULONG DllNameSize;
+ USHORT OrdinalNumber = 0;
+ USHORT HintIndex;
+ ULONG ExportSize;
+ PIMAGE_EXPORT_DIRECTORY Exports;
+ ULONG ExportsBase;
+ PULONG AddressOfNames;
+ PUSHORT AddressOfOrdinals;
+ PULONG AddressOfPointers;
+ LPSTR ExportName;
+ ULONG ForwardedAddress;
+ PBOUND_FORWARDER_REFS BoundForwarder;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader32 = NULL;
+
+NextForwarder:
+
+ /* Get the DLL Name */
+ TempDllName = ForwarderString;
+ while (*TempDllName && *TempDllName != '.') TempDllName++;
+ DllNameSize = (ULONG) (TempDllName - ForwarderString);
+ lstrcpynA(DllName, ForwarderString, DllNameSize + 1);
+
+ /* Append .DLL extension */
+ DllName[DllNameSize] = '\0';
+ strcat(DllName, ".DLL" );
+
+ /* Load it */
+ TRACE("Loading the Thunk Library: %s \n", DllName);
+ LoadedLibrary = ImageLoad(DllName, DllPath);
+ TempDllName += 1;
+
+ /* Return whatever we got back in case of failure*/
+ if (!LoadedLibrary) return (ULONG)ForwarderString;
+ TRACE("It Loaded at: %p \n", LoadedLibrary->MappedAddress);
+
+ /* Load Exports */
+ Exports = RtlImageDirectoryEntryToData((HMODULE)LoadedLibrary->MappedAddress, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportSize);
+
+ /* Get the Pointers to the Tables */
+ AddressOfNames = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfNames,
+ &LoadedLibrary->LastRvaSection);
+ AddressOfOrdinals = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfNameOrdinals,
+ &LoadedLibrary->LastRvaSection);
+ AddressOfPointers = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfFunctions,
+ &LoadedLibrary->LastRvaSection);
+
+ /* Get the Optional Header */
+ OptionalHeader32 = &LoadedLibrary->FileHeader->OptionalHeader;
+
+ /* Get the Ordinal Number */
+ for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++) {
+
+ /* Get the Export Name */
+ ExportName = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ AddressOfNames[HintIndex],
+ &LoadedLibrary->LastRvaSection);
+
+ /* Check if it matches */
+ if (!strcmp(TempDllName, ExportName)) {
+ OrdinalNumber = AddressOfOrdinals[HintIndex];
+ break;
+ }
+ }
+
+ do {
+ /* Get the Forwarded Address */
+ ForwardedAddress = AddressOfPointers[OrdinalNumber] + OptionalHeader32->ImageBase;
+
+ /* Load the First Bound Forward Structure */
+ BoundForwarder = BoundImportDescriptor->Forwarders;
+
+ /* Check if we already have the Module Name written */
+ while (BoundForwarder->ModuleName) {
+ if (!lstrcmpiA(DllName, BoundForwarder->ModuleName)) break;
+ BoundForwarder++;
+ }
+
+ if (!BoundForwarder->ModuleName) {
+
+ /* Save Library Name in Bound Libraries Buffer */
+ strcat((char *)BoundLibrariesPointer, DllName);
+
+ /* Set Data */
+ BoundForwarder->ModuleName = BoundLibrariesPointer;
+ BoundForwarder->TimeDateStamp = LoadedLibrary->FileHeader->FileHeader.TimeDateStamp;
+
+ /* Next String */
+ BoundLibrariesPointer = BoundLibrariesPointer + strlen((char *)BoundLibrariesPointer) + 1;
+ BoundImportDescriptor->ForwaderReferences += 1;
+ }
+
+ /* Load DLL's Exports */
+ ExportsBase = (ULONG)RtlImageDirectoryEntryToData ((HMODULE)LoadedLibrary->MappedAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize) -
+ (ULONG_PTR)LoadedLibrary->MappedAddress;
+ ExportsBase += OptionalHeader32->ImageBase;
+
+ TRACE("I've thunked it\n");
+
+ /* Is this yet another Forward? */
+ if (ForwardedAddress > ExportsBase && ForwardedAddress < (ExportsBase + ExportSize)) {
+ ForwarderString = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ AddressOfPointers[OrdinalNumber],
+ &LoadedLibrary->LastRvaSection);
+ goto NextForwarder;
+ }
+ }
+ while (0);
+ return ForwardedAddress;
+}
+
+/*
+ * BindpBindThunk
+ *
+ * FUNCTION:
+ * Finds the pointer of the Imported function, and writes it into the Thunk,
+ * thus making the Thunk Bound.
+ *
+ * ARGUMENTS:
+ * Thunk - Current Thunk in Unbound File
+ * File - File containing the Thunk
+ * BoundThunk - Pointer to the corresponding Bound Thunk
+ * LoadedLibrary - Library containing the Exported Function
+ * Exports - Export Directory of LoadedLibrary
+ * BoundImportDescriptor - Internal Bound Import Descriptor of LoadedLibrary
+ * DllPath - DLL Search Path
+ *
+ * RETURNS:
+ * TRUE if Suceeded
+ */
+BOOL
+WINAPI
+BindpBindThunk(
+ PIMAGE_THUNK_DATA Thunk,
+ PLOADED_IMAGE File,
+ PIMAGE_THUNK_DATA BoundThunk,
+ PLOADED_IMAGE LoadedLibrary,
+ PIMAGE_EXPORT_DIRECTORY Exports,
+ PBOUND_IMPORT_DESCRIPTOR BoundImportDescriptor,
+ LPSTR DllPath
+ )
+{
+ PULONG AddressOfNames;
+ PUSHORT AddressOfOrdinals;
+ PULONG AddressOfPointers;
+ PIMAGE_IMPORT_BY_NAME ImportName;
+ ULONG OrdinalNumber = 0;
+ USHORT HintIndex;
+ LPSTR ExportName;
+ ULONG ExportsBase;
+ ULONG ExportSize;
+ UCHAR NameBuffer[32];
+ PIMAGE_OPTIONAL_HEADER OptionalHeader32 = NULL;
+ PIMAGE_OPTIONAL_HEADER LibraryOptionalHeader32 = NULL;
+
+ /* Get the Pointers to the Tables */
+ AddressOfNames = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfNames,
+ &LoadedLibrary->LastRvaSection);
+ AddressOfOrdinals = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfNameOrdinals,
+ &LoadedLibrary->LastRvaSection);
+ AddressOfPointers = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ Exports->AddressOfFunctions,
+ &LoadedLibrary->LastRvaSection);
+
+ TRACE("Binding a Thunk\n");
+
+ /* Get the Optional Header */
+ OptionalHeader32 = &File->FileHeader->OptionalHeader;
+ LibraryOptionalHeader32 = &LoadedLibrary->FileHeader->OptionalHeader;
+
+ /* Import by Ordinal */
+ if (IMAGE_SNAP_BY_ORDINAL(Thunk->u1.Ordinal) == TRUE) {
+ OrdinalNumber = (IMAGE_ORDINAL(Thunk->u1.Ordinal) - Exports->Base);
+ ImportName = (PIMAGE_IMPORT_BY_NAME)NameBuffer;
+ } else {
+
+ /* Import by Name */
+ ImportName = ImageRvaToVa (File->FileHeader,
+ File->MappedAddress,
+ (ULONG)Thunk->u1.AddressOfData,
+ &File->LastRvaSection);
+
+ for (HintIndex = 0; HintIndex < Exports->NumberOfNames; HintIndex++) {
+
+ /* Get the Export Name */
+ ExportName = ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ (ULONG)AddressOfNames[HintIndex],
+ &LoadedLibrary->LastRvaSection);
+
+ /* Check if it's the one we want */
+ if (!strcmp((CHAR*)ImportName->Name, ExportName)) {
+ OrdinalNumber = AddressOfOrdinals[HintIndex];
+ break;
+ }
+ }
+ }
+
+ /* Fail if we still didn't find anything */
+ if (!OrdinalNumber) return FALSE;
+
+ /* Write the Pointer */
+ BoundThunk->u1.Function = (DWORD)(AddressOfPointers[OrdinalNumber] + LibraryOptionalHeader32->ImageBase);
+
+ /* Load DLL's Exports */
+ ExportsBase = (ULONG)RtlImageDirectoryEntryToData ((HMODULE)LoadedLibrary->MappedAddress,
+ TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &ExportSize) -
+ (ULONG_PTR)LoadedLibrary->MappedAddress;
+ /* RVA to VA */
+ ExportsBase += LibraryOptionalHeader32->ImageBase;
+
+ /* Check if the Export is forwarded (meaning that it's pointer is inside the Export Table) */
+ if ((ULONG)BoundThunk->u1.Function > ExportsBase && (ULONG)BoundThunk->u1.Function < (ExportsBase + ExportSize)) {
+
+ TRACE("This Thunk is a forward...calling forward thunk bounder\n");
+
+ /* Replace the Forwarder String by the actual Pointer */
+ BoundThunk->u1.Function = (DWORD)BindpAddBoundForwarder (BoundImportDescriptor,
+ DllPath,
+ ImageRvaToVa (LoadedLibrary->FileHeader,
+ LoadedLibrary->MappedAddress,
+ AddressOfPointers[OrdinalNumber],
+ &LoadedLibrary->LastRvaSection));
+
+ }
+
+ /* Return Success */
+ return TRUE;
+}
+
+/*
+ * BindpCreateBoundImportSection
+ *
+ * FUNCTION:
+ * Creates a 32-bit PE Bound Import Table
+ *
+ * ARGUMENTS:
+ * BoundImportDescriptor - Pointer to the Bound Import Table
+ * BoundImportsSize - Size of the Bound Import Table
+ *
+ * RETURNS:
+ * PIMAGE_BOUND_IMPORT_DESCRIPTOR - The Bound Import Table
+ */
+PIMAGE_BOUND_IMPORT_DESCRIPTOR
+WINAPI
+BindpCreateBoundImportSection(
+ PULONG BoundImportDescriptor,
+ PULONG BoundImportsSize
+ )
+{
+ ULONG BoundLibraryNamesSize, BoundImportTableSize;
+ PBOUND_FORWARDER_REFS BoundForwarder;
+ PBOUND_IMPORT_DESCRIPTOR CurrentBoundImportDescriptor;
+ PVOID BoundLibraryNames;
+ PIMAGE_BOUND_IMPORT_DESCRIPTOR CurrentBoundImportTableEntry, BoundImportTable;
+ PIMAGE_BOUND_FORWARDER_REF NewForwarder;
+
+ /* Zero the Sizes */
+ *BoundImportsSize = 0;
+ BoundLibraryNamesSize = 0;
+ BoundImportTableSize = 0;
+
+ /* Start with the first Internal Descriptor */
+ CurrentBoundImportDescriptor = (PBOUND_IMPORT_DESCRIPTOR)BoundImportDescriptor;
+
+ /* Loop through every Descriptor we loaded */
+ while (CurrentBoundImportDescriptor->ModuleName) {
+
+ /* Add to the size of the Bound Import Table */
+ BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
+
+ /* Check Forwarders */
+ BoundForwarder = CurrentBoundImportDescriptor->Forwarders;
+ while (BoundForwarder->ModuleName) {
+
+ /* Add to size of Bound Import Table */
+ BoundImportTableSize += sizeof(IMAGE_BOUND_FORWARDER_REF);
+
+ /* Next Forwarder */
+ BoundForwarder++;
+ }
+
+ /* Read Next Internal Descriptor */
+ CurrentBoundImportDescriptor++;
+ }
+
+ /* Add Terminator for PE Loader*/
+ BoundImportTableSize += sizeof(IMAGE_BOUND_IMPORT_DESCRIPTOR);
+
+ /* Name of Libraries Bound in Bound Import Table */
+ BoundLibraryNamesSize = ((ULONG)BoundLibrariesPointer - (ULONG)(&BoundLibraries));
+
+ /* Size of the whole table, dword aligned */
+ *BoundImportsSize = BoundImportTableSize +
+ ((BoundLibraryNamesSize + sizeof(ULONG) - 1) & ~(sizeof(ULONG)-1));
+
+ /* Allocate it */
+ BoundImportTable = GlobalAlloc(GMEM_ZEROINIT, *BoundImportsSize);
+
+ /* Pointer Library Names inside the Bound Import Table */
+ BoundLibraryNames = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)((ULONG_PTR)BoundImportTable +
+ BoundImportTableSize);
+
+ /* Copy the Library Names */
+ RtlCopyMemory(BoundLibraryNames, BoundLibraries, BoundLibraryNamesSize);
+
+ /* Go back to first Internal Descriptor and load first entry in the Bound Import Table */
+ CurrentBoundImportTableEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)BoundImportTable;
+ CurrentBoundImportDescriptor = (PBOUND_IMPORT_DESCRIPTOR)BoundImportDescriptor;
+
+ /* Copy the data from our Internal Structure to the Bound Import Table */
+ while (CurrentBoundImportDescriptor->ModuleName) {
+ CurrentBoundImportTableEntry->TimeDateStamp = CurrentBoundImportDescriptor->TimeDateStamp;
+ CurrentBoundImportTableEntry->OffsetModuleName = (USHORT)(BoundImportTableSize +
+ (CurrentBoundImportDescriptor->ModuleName -
+ (LPSTR) BoundLibraries));
+ CurrentBoundImportTableEntry->NumberOfModuleForwarderRefs = CurrentBoundImportDescriptor->ForwaderReferences;
+
+ /* Copy the data from our Forwader Entries to the Bound Import Table */
+ NewForwarder = (PIMAGE_BOUND_FORWARDER_REF)(CurrentBoundImportTableEntry+1);
+ BoundForwarder = CurrentBoundImportDescriptor->Forwarders;
+ while (BoundForwarder->ModuleName) {
+ NewForwarder->TimeDateStamp =BoundForwarder->TimeDateStamp;
+ NewForwarder->OffsetModuleName = (USHORT)(BoundImportTableSize +
+ (BoundForwarder->ModuleName -
+ (LPSTR) BoundLibraries));
+ NewForwarder++;
+ BoundForwarder++;
+ }
+
+ /* Move to next Bound Import Table Entry */
+ CurrentBoundImportTableEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)NewForwarder;
+
+ /* move to next Internal Descriptor */
+ CurrentBoundImportDescriptor++;
+ }
+
+ /* Now put the pointer back at the beginning and clear the buffer */
+ RtlZeroMemory(BoundLibraries, 4096);
+ BoundLibrariesPointer = BoundLibraries;
+
+ return BoundImportTable;
+}
+
+/*
+ * BindpWalkAndBindImports
+ *
+ * FUNCTION:
+ * Does the actual Binding of the Imports and Forward-Referencing
+ *
+ * ARGUMENTS:
+ * File - Name of Imagefile to Bind
+ * DllPath - Path to search DLL Files in, can be NULL to use Default
+ *
+ * RETURNS:
+ * Nothing
+ */
+VOID
+WINAPI
+BindpWalkAndBindImports(
+ PLOADED_IMAGE File,
+ LPSTR DllPath
+ )
+{
+ PIMAGE_IMPORT_DESCRIPTOR Imports;
+ PIMAGE_EXPORT_DIRECTORY Exports;
+ ULONG SizeOfImports;
+ ULONG SizeOfExports;
+ ULONG SizeOfThunks;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader32 = NULL;
+ PIMAGE_FILE_HEADER FileHeader;
+ LPSTR ImportedLibrary;
+ PLOADED_IMAGE LoadedLibrary;
+ PBOUND_IMPORT_DESCRIPTOR BoundImportDescriptor = NULL;
+ PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundImportTable;
+ PIMAGE_THUNK_DATA Thunks, TempThunk;
+ PIMAGE_THUNK_DATA BoundThunks, TempBoundThunk;
+ ULONG ThunkCount = 0;
+ ULONG Thunk;
+ ULONG BoundImportTableSize;
+ ULONG VirtBytesFree, HeaderBytesFree, FirstFreeByte, PhysBytesFree;
+
+ TRACE("BindpWalkAndBindImports Called\n");
+
+ /* Load the Import Descriptor */
+ Imports = RtlImageDirectoryEntryToData ((HMODULE)File->MappedAddress,
+ FALSE,
+ IMAGE_DIRECTORY_ENTRY_IMPORT,
+ &SizeOfImports);
+
+ /* Read the File Header */
+ FileHeader = &File->FileHeader->FileHeader;
+ OptionalHeader32 = &File->FileHeader->OptionalHeader;
+
+ /* Support for up to 32 imported DLLs */
+ BoundImportDescriptors = GlobalAlloc(GMEM_ZEROINIT, 32* sizeof(*BoundImportDescriptor));
+
+ TRACE("BoundImportDescriptors Allocated\n");
+
+ /* For each Import */
+ for(; Imports->Name ; Imports++) {
+
+ /* Which DLL is being Imported */
+ ImportedLibrary = ImageRvaToVa (File->FileHeader,
+ File->MappedAddress,
+ Imports->Name,
+ &File->LastRvaSection);
+
+ TRACE("Loading Imported DLL: %s \n", ImportedLibrary);
+
+ /* Load the DLL */
+ LoadedLibrary = ImageLoad(ImportedLibrary, DllPath);
+
+ TRACE("DLL Loaded at: %p \n", LoadedLibrary->MappedAddress);
+
+ /* Now load the Exports */
+ Exports = RtlImageDirectoryEntryToData ((HMODULE)LoadedLibrary->MappedAddress,
+ FALSE,
+ IMAGE_DIRECTORY_ENTRY_EXPORT,
+ &SizeOfExports);
+
+ /* And load the Thunks */
+ Thunks = ImageRvaToVa (File->FileHeader,
+ File->MappedAddress,
+ (DWORD)Imports->OriginalFirstThunk,
+ &File->LastRvaSection);
+
+ /* No actual Exports (UPX Packer can do this */
+ if (!Thunks) continue;
+
+ TRACE("Creating Bound Descriptor for this DLL\n");
+
+ /* Create Bound Import Descriptor */
+ BoundImportDescriptor = BindpCreateBoundImportDescriptor (ImportedLibrary,
+ LoadedLibrary,
+ BoundImportDescriptors);
+
+ /* Count how many Thunks we have */
+ ThunkCount = 0;
+ TempThunk = Thunks;
+ while (TempThunk->u1.AddressOfData) {
+ ThunkCount++;
+ TempThunk++;
+ }
+
+ /* Allocate Memory for the Thunks we will Bind */
+ SizeOfThunks = ThunkCount * sizeof(*TempBoundThunk);
+ BoundThunks = GlobalAlloc(GMEM_ZEROINIT, SizeOfThunks);
+
+ TRACE("Binding Thunks %p\n",BoundThunks);
+
+ /* Bind the Thunks */
+ TempThunk = Thunks;
+ TempBoundThunk = BoundThunks;
+ for (Thunk=0; Thunk < ThunkCount; Thunk++) {
+ BindpBindThunk (TempThunk,
+ File,
+ TempBoundThunk,
+ LoadedLibrary,
+ Exports,
+ BoundImportDescriptor,
+ DllPath);
+ TempThunk++;
+ TempBoundThunk++;
+ }
+
+ /* Load the Second Thunk Array */
+ TempThunk = ImageRvaToVa (File->FileHeader,
+ File->MappedAddress,
+ (ULONG)Imports->FirstThunk,
+ &File->LastRvaSection);
+
+ TRACE("Copying Bound Thunks %p\n",TempThunk);
+
+ /* Copy the Pointers */
+ if (memcmp(TempThunk, BoundThunks, SizeOfThunks)) {
+ RtlCopyMemory(TempThunk, BoundThunks, SizeOfThunks);
+ }
+
+ /* Set the TimeStamp */
+ if (Imports->TimeDateStamp != 0xFFFFFFFF) {
+ Imports->TimeDateStamp = 0xFFFFFFFF;
+ }
+
+ /* Free the Allocated Memory */
+ GlobalFree(BoundThunks);
+
+ TRACE("Moving to next File\n");
+ }
+
+ TRACE("Creating Bound Import Section\n");
+
+ /* Create the Bound Import Table */
+ BoundImportTable = BindpCreateBoundImportSection(BoundImportDescriptors, &BoundImportTableSize);
+
+ /* Zero out the Bound Import Table */
+ File->FileHeader->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = 0;
+ File->FileHeader->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = 0;
+
+ /* Check if we have enough space */
+ FirstFreeByte = GetImageUnusedHeaderBytes(File, &VirtBytesFree);
+ HeaderBytesFree = File->Sections->VirtualAddress -
+ File->FileHeader->OptionalHeader.SizeOfHeaders + VirtBytesFree;
+ PhysBytesFree = File->Sections->PointerToRawData -
+ File->FileHeader->OptionalHeader.SizeOfHeaders + VirtBytesFree;
+
+ TRACE("Calculating Space, %lx bytes free\n",PhysBytesFree);
+
+ if (BoundImportTableSize > VirtBytesFree) {
+ if (BoundImportTableSize > HeaderBytesFree) {
+ TRACE("Only %lx bytes free. Not enough Space\n",HeaderBytesFree);
+ return; /* Fail...not enough space */
+ }
+ if (BoundImportTableSize <= PhysBytesFree) {
+
+ TRACE("Header Recalculation\n");
+ /* We have enough NULLs to add it, simply enlarge header data */
+ File->FileHeader->OptionalHeader.SizeOfHeaders = File->FileHeader->OptionalHeader.SizeOfHeaders -
+ VirtBytesFree +
+ BoundImportTableSize +
+ ((File->FileHeader->OptionalHeader.FileAlignment - 1)
+ & ~(File->FileHeader->OptionalHeader.FileAlignment - 1));
+
+ } else {
+
+ /* Resize the Headers */
+ FIXME("Add support for Header Resizing\n");
+
+ /* Recalculate Headers */
+ FileHeader = &File->FileHeader->FileHeader;
+ OptionalHeader32 = &File->FileHeader->OptionalHeader;
+ }
+ }
+
+ /* Set Bound Import Table Data */
+ File->FileHeader->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].VirtualAddress = FirstFreeByte;
+ File->FileHeader->OptionalHeader.DataDirectory
+ [IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT].Size = BoundImportTableSize;
+
+ TRACE("Copying Bound Import Table\n");
+
+ /* Copy the Bound Import Table */
+ RtlCopyMemory(File->MappedAddress + FirstFreeByte, BoundImportTable, BoundImportTableSize);
+
+ /* Free out local copy */
+ GlobalFree(BoundImportTable);
+}
/***********************************************************************
* BindImage (IMAGEHLP.@)
@@ -42,21 +703,80 @@
return BindImageEx(0, ImageName, DllPath, SymbolPath, NULL);
}
-/***********************************************************************
- * BindImageEx (IMAGEHLP.@)
+/*
+ * BindImageEx
+ *
+ * FUNCTION:
+ * Binds a PE Image File to its imported Libraries
+ * ARGUMENTS:
+ * Flags - Caller Specified Flags
+ * ImageName - Name of Imagefile to Bind
+ * DllPath - Path to search DLL Files in, can be NULL to use Default
+ * SymbolPath - Path to search Symbol Files in, can be NULL to use Default
+ * StatusRoutine - Callback routine to notify of Bind Events, can be NULL to disable.
+ *
+ * RETURNS:
+ * TRUE if Success.
*/
-BOOL WINAPI BindImageEx(
- DWORD Flags, LPSTR ImageName, LPSTR DllPath, LPSTR SymbolPath,
- PIMAGEHLP_STATUS_ROUTINE StatusRoutine)
-{
- FIXME("(%ld, %s, %s, %s, %p): stub\n",
- Flags, debugstr_a(ImageName), debugstr_a(DllPath),
- debugstr_a(SymbolPath), StatusRoutine
- );
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
-}
+BOOL
+WINAPI
+BindImageEx(
+ IN DWORD Flags,
+ IN LPSTR ImageName,
+ IN LPSTR DllPath,
+ IN LPSTR SymbolPath,
+ IN PIMAGEHLP_STATUS_ROUTINE StatusRoutine
+ )
+{
+ LOADED_IMAGE FileData;
+ PLOADED_IMAGE File;
+ ULONG CheckSum, HeaderSum, OldChecksum;
+ SYSTEMTIME SystemTime;
+ FILETIME LastWriteTime;
+
+ TRACE("BindImageEx Called for: %s \n", ImageName);
+
+ /* Set and Clear Buffer */
+ File = &FileData;
+ RtlZeroMemory(File, sizeof(*File));
+
+ /* Request Image Data */
+ if (MapAndLoad(ImageName, DllPath, File, TRUE, FALSE)) {
+
+ TRACE("Image Mapped and Loaded\n");
+
+ /* Read Import Table */
+ BindpWalkAndBindImports(File, DllPath);
+
+ TRACE("Binding Completed, getting Checksum\n");
+
+ /* Update Checksum */
+ OldChecksum = File->FileHeader->OptionalHeader.CheckSum;
+ CheckSumMappedFile (File->MappedAddress,
+ GetFileSize(File->hFile, NULL),
+ &HeaderSum,
+ &CheckSum);
+ File->FileHeader->OptionalHeader.CheckSum = CheckSum;
+
+ TRACE("Saving Changes to file\n");
+
+ /* Save Changes */
+ UnmapViewOfFile(File->MappedAddress);
+
+ TRACE("Setting time\n");
+
+ /* Save new Modified Time */
+ GetSystemTime(&SystemTime);
+ SystemTimeToFileTime(&SystemTime, &LastWriteTime);
+ SetFileTime(File->hFile, NULL, NULL, &LastWriteTime);
+
+ /* Close Handle */
+ CloseHandle(File->hFile);
+ }
+ TRACE("Done\n");
+ return TRUE;
+}
/***********************************************************************
* CheckSum (internal)
More information about the wine-patches
mailing list