[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