ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

peloader.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:         FreeLoader
00003  * LICENSE:         GPL - See COPYING in the top level directory
00004  * FILE:            freeldr/winldr/peloader.c
00005  * PURPOSE:         Provides routines for loading PE files. To be merged with
00006  *                  arch/i386/loader.c in future
00007  *                  This article was very handy during development:
00008  *                  http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
00009  * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)
00010  *                  The source code in this file is based on the work of respective
00011  *                  authors of PE loading code in ReactOS and Brian Palmer and
00012  *                  Alex Ionescu's arch/i386/loader.c, and my research project
00013  *                  (creating a native EFI loader for Windows)
00014  */
00015 
00016 /* INCLUDES ***************************************************************/
00017 #include <freeldr.h>
00018 #include <debug.h>
00019 
00020 DBG_DEFAULT_CHANNEL(PELOADER);
00021 
00022 static BOOLEAN
00023 WinLdrpCompareDllName(IN PCH DllName,
00024                       IN PUNICODE_STRING UnicodeName);
00025 
00026 static BOOLEAN
00027 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead,
00028                       IN PVOID DllBase,
00029                       IN PVOID ImageBase,
00030                       IN PIMAGE_THUNK_DATA ThunkData,
00031                       IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
00032                       IN ULONG ExportSize,
00033                       IN BOOLEAN ProcessForwards);
00034 
00035 static BOOLEAN
00036 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead,
00037                                 PCCH DirectoryPath,
00038                                 PCH ImportName,
00039                                 PLDR_DATA_TABLE_ENTRY *DataTableEntry);
00040 
00041 static BOOLEAN
00042 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead,
00043                               IN PVOID DllBase,
00044                               IN PVOID ImageBase,
00045                               IN PIMAGE_THUNK_DATA ThunkData);
00046 
00047 
00048 
00049 /* FUNCTIONS **************************************************************/
00050 
00051 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
00052 BOOLEAN
00053 WinLdrCheckForLoadedDll(IN OUT PLIST_ENTRY ModuleListHead,
00054                         IN PCH DllName,
00055                         OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
00056 {
00057     PLDR_DATA_TABLE_ENTRY DataTableEntry;
00058     LIST_ENTRY *ModuleEntry;
00059 
00060     TRACE("WinLdrCheckForLoadedDll: DllName %s, LoadedEntry: %X\n",
00061         DllName, LoadedEntry);
00062 
00063     /* Just go through each entry in the LoadOrderList and compare loaded module's
00064        name with a given name */
00065     ModuleEntry = ModuleListHead->Flink;
00066     while (ModuleEntry != ModuleListHead)
00067     {
00068         /* Get pointer to the current DTE */
00069         DataTableEntry = CONTAINING_RECORD(ModuleEntry,
00070             LDR_DATA_TABLE_ENTRY,
00071             InLoadOrderLinks);
00072 
00073         TRACE("WinLdrCheckForLoadedDll: DTE %p, EP %p, base %p name '%ws'\n",
00074             DataTableEntry, DataTableEntry->EntryPoint, DataTableEntry->DllBase,
00075             VaToPa(DataTableEntry->BaseDllName.Buffer));
00076 
00077         /* Compare names */
00078         if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))
00079         {
00080             /* Yes, found it, report pointer to the loaded module's DTE
00081                to the caller and increase load count for it */
00082             *LoadedEntry = DataTableEntry;
00083             DataTableEntry->LoadCount++;
00084             TRACE("WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry);
00085             return TRUE;
00086         }
00087 
00088         /* Go to the next entry */
00089         ModuleEntry = ModuleEntry->Flink;
00090     }
00091 
00092     /* Nothing found */
00093     return FALSE;
00094 }
00095 
00096 BOOLEAN
00097 WinLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead,
00098                                 IN PCCH DirectoryPath,
00099                                 IN PLDR_DATA_TABLE_ENTRY ScanDTE)
00100 {
00101     PLDR_DATA_TABLE_ENTRY DataTableEntry;
00102     PIMAGE_IMPORT_DESCRIPTOR ImportTable;
00103     ULONG ImportTableSize;
00104     PCH ImportName;
00105     BOOLEAN Status;
00106 
00107     /* Get a pointer to the import table of this image */
00108     ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),
00109         TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
00110 
00111     {
00112         UNICODE_STRING BaseName;
00113         BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer);
00114         BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength;
00115         BaseName.Length = ScanDTE->BaseDllName.Length;
00116         TRACE("WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
00117             &BaseName, ImportTable);
00118     }
00119 
00120     /* If image doesn't have any import directory - just return success */
00121     if (ImportTable == NULL)
00122         return TRUE;
00123 
00124     /* Loop through all entries */
00125     for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
00126     {
00127         /* Get pointer to the name */
00128         ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
00129         TRACE("WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName);
00130 
00131         /* In case we get a reference to ourselves - just skip it */
00132         if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))
00133             continue;
00134 
00135         /* Load the DLL if it is not already loaded */
00136         if (!WinLdrCheckForLoadedDll(ModuleListHead, ImportName, &DataTableEntry))
00137         {
00138             Status = WinLdrpLoadAndScanReferencedDll(ModuleListHead,
00139                 DirectoryPath,
00140                 ImportName,
00141                 &DataTableEntry);
00142 
00143             if (!Status)
00144             {
00145                 ERR("WinLdrpLoadAndScanReferencedDll() failed\n");
00146                 return Status;
00147             }
00148         }
00149 
00150         /* Scan its import address table */
00151         Status = WinLdrpScanImportAddressTable(
00152             ModuleListHead,
00153             DataTableEntry->DllBase,
00154             ScanDTE->DllBase,
00155             (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk));
00156 
00157         if (!Status)
00158         {
00159             ERR("WinLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n",
00160                 ImportName, DirectoryPath);
00161             return Status;
00162         }
00163     }
00164 
00165     return TRUE;
00166 }
00167 
00168 BOOLEAN
00169 WinLdrAllocateDataTableEntry(IN OUT PLIST_ENTRY ModuleListHead,
00170                              IN PCCH BaseDllName,
00171                              IN PCCH FullDllName,
00172                              IN PVOID BasePA,
00173                              OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
00174 {
00175     PVOID BaseVA = PaToVa(BasePA);
00176     PWSTR Buffer;
00177     PLDR_DATA_TABLE_ENTRY DataTableEntry;
00178     PIMAGE_NT_HEADERS NtHeaders;
00179     USHORT Length;
00180     TRACE("WinLdrAllocateDataTableEntry(, '%s', '%s', %p)\n",
00181        BaseDllName, FullDllName, BasePA);
00182 
00183     /* Allocate memory for a data table entry, zero-initialize it */
00184     DataTableEntry = (PLDR_DATA_TABLE_ENTRY)MmHeapAlloc(sizeof(LDR_DATA_TABLE_ENTRY));
00185     if (DataTableEntry == NULL)
00186         return FALSE;
00187     RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));
00188 
00189     /* Get NT headers from the image */
00190     NtHeaders = RtlImageNtHeader(BasePA);
00191 
00192     /* Initialize corresponding fields of DTE based on NT headers value */
00193     DataTableEntry->DllBase = BaseVA;
00194     DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
00195     DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);
00196     DataTableEntry->SectionPointer = 0;
00197     DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
00198 
00199     /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
00200        by simple conversion - copying each character */
00201     Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
00202     Buffer = (PWSTR)MmHeapAlloc(Length);
00203     if (Buffer == NULL)
00204     {
00205         MmHeapFree(DataTableEntry);
00206         return FALSE;
00207     }
00208     RtlZeroMemory(Buffer, Length);
00209 
00210     DataTableEntry->BaseDllName.Length = Length;
00211     DataTableEntry->BaseDllName.MaximumLength = Length;
00212     DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);
00213     while (*BaseDllName != 0)
00214     {
00215         *Buffer++ = *BaseDllName++;
00216     }
00217 
00218     /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
00219        using the same method */
00220     Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
00221     Buffer = (PWSTR)MmHeapAlloc(Length);
00222     if (Buffer == NULL)
00223     {
00224         MmHeapFree(DataTableEntry);
00225         return FALSE;
00226     }
00227     RtlZeroMemory(Buffer, Length);
00228 
00229     DataTableEntry->FullDllName.Length = Length;
00230     DataTableEntry->FullDllName.MaximumLength = Length;
00231     DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);
00232     while (*FullDllName != 0)
00233     {
00234         *Buffer++ = *FullDllName++;
00235     }
00236 
00237     /* Initialize what's left - LoadCount which is 1, and set Flags so that
00238        we know this entry is processed */
00239     DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
00240     DataTableEntry->LoadCount = 1;
00241 
00242     /* Insert this DTE to a list in the LPB */
00243     InsertTailList(ModuleListHead, &DataTableEntry->InLoadOrderLinks);
00244     TRACE("Inserting DTE %p, name='%S' DllBase=%p \n", DataTableEntry,
00245           DataTableEntry->BaseDllName.Buffer, DataTableEntry->DllBase);
00246 
00247     /* Save pointer to a newly allocated and initialized entry */
00248     *NewEntry = DataTableEntry;
00249 
00250     /* Return success */
00251     return TRUE;
00252 }
00253 
00254 /* WinLdrLoadImage loads the specified image from the file (it doesn't
00255    perform any additional operations on the filename, just directly
00256    calls the file I/O routines), and relocates it so that it's ready
00257    to be used when paging is enabled.
00258    Addressing mode: physical
00259  */
00260 BOOLEAN
00261 WinLdrLoadImage(IN PCHAR FileName,
00262                 TYPE_OF_MEMORY MemoryType,
00263                 OUT PVOID *ImageBasePA)
00264 {
00265     ULONG FileId;
00266     PVOID PhysicalBase;
00267     PVOID VirtualBase = NULL;
00268     UCHAR HeadersBuffer[SECTOR_SIZE * 2];
00269     PIMAGE_NT_HEADERS NtHeaders;
00270     PIMAGE_SECTION_HEADER SectionHeader;
00271     ULONG VirtualSize, SizeOfRawData, NumberOfSections;
00272     LONG Status;
00273     LARGE_INTEGER Position;
00274     ULONG i, BytesRead;
00275     TRACE("WinLdrLoadImage(%s, %ld, *)\n", FileName, MemoryType);
00276 
00277     /* Open the image file */
00278     Status = ArcOpen(FileName, OpenReadOnly, &FileId);
00279     if (Status != ESUCCESS)
00280     {
00281         //UiMessageBox("Can not open the file");
00282         return FALSE;
00283     }
00284 
00285     /* Load the first 2 sectors of the image so we can read the PE header */
00286     Status = ArcRead(FileId, HeadersBuffer, SECTOR_SIZE * 2, &BytesRead);
00287     if (Status != ESUCCESS)
00288     {
00289         UiMessageBox("Error reading from file");
00290         ArcClose(FileId);
00291         return FALSE;
00292     }
00293 
00294     /* Now read the MZ header to get the offset to the PE Header */
00295     NtHeaders = RtlImageNtHeader(HeadersBuffer);
00296 
00297     if (!NtHeaders)
00298     {
00299         //Print(L"Error - no NT header found in %s\n", FileName);
00300         UiMessageBox("Error - no NT header found");
00301         ArcClose(FileId);
00302         return FALSE;
00303     }
00304 
00305     /* Ensure this is executable image */
00306     if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
00307     {
00308         //Print(L"Not an executable image %s\n", FileName);
00309         UiMessageBox("Not an executable image");
00310         ArcClose(FileId);
00311         return FALSE;
00312     }
00313 
00314     /* Store number of sections to read and a pointer to the first section */
00315     NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
00316     SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
00317 
00318     /* Try to allocate this memory, if fails - allocate somewhere else */
00319     PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
00320                        (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
00321                        MemoryType);
00322 
00323     if (PhysicalBase == NULL)
00324     {
00325         /* It's ok, we don't panic - let's allocate again at any other "low" place */
00326         PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
00327 
00328         if (PhysicalBase == NULL)
00329         {
00330             //Print(L"Failed to alloc pages for image %s\n", FileName);
00331             UiMessageBox("Failed to alloc pages for image");
00332             ArcClose(FileId);
00333             return FALSE;
00334         }
00335     }
00336 
00337     /* This is the real image base - in form of a virtual address */
00338     VirtualBase = PaToVa(PhysicalBase);
00339 
00340     TRACE("Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase);
00341 
00342     /* Set to 0 position and fully load the file image */
00343     Position.HighPart = Position.LowPart = 0;
00344     Status = ArcSeek(FileId, &Position, SeekAbsolute);
00345     if (Status != ESUCCESS)
00346     {
00347         UiMessageBox("Error seeking to start of file");
00348         ArcClose(FileId);
00349         return FALSE;
00350     }
00351 
00352     Status = ArcRead(FileId, PhysicalBase, NtHeaders->OptionalHeader.SizeOfHeaders, &BytesRead);
00353 
00354     if (Status != ESUCCESS)
00355     {
00356         //Print(L"Error reading headers %s\n", FileName);
00357         UiMessageBox("Error reading headers");
00358         ArcClose(FileId);
00359         return FALSE;
00360     }
00361 
00362     /* Reload the NT Header */
00363     NtHeaders = RtlImageNtHeader(PhysicalBase);
00364 
00365     /* Load the first section */
00366     SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
00367 
00368     /* Fill output parameters */
00369     *ImageBasePA = PhysicalBase;
00370 
00371     /* Walk through each section and read it (check/fix any possible
00372        bad situations, if they arise) */
00373     for (i = 0; i < NumberOfSections; i++)
00374     {
00375         VirtualSize = SectionHeader->Misc.VirtualSize;
00376         SizeOfRawData = SectionHeader->SizeOfRawData;
00377 
00378         /* Handle a case when VirtualSize equals 0 */
00379         if (VirtualSize == 0)
00380             VirtualSize = SizeOfRawData;
00381 
00382         /* If PointerToRawData is 0, then force its size to be also 0 */
00383         if (SectionHeader->PointerToRawData == 0)
00384         {
00385             SizeOfRawData = 0;
00386         }
00387         else
00388         {
00389             /* Cut the loaded size to the VirtualSize extents */
00390             if (SizeOfRawData > VirtualSize)
00391                 SizeOfRawData = VirtualSize;
00392         }
00393 
00394         /* Actually read the section (if its size is not 0) */
00395         if (SizeOfRawData != 0)
00396         {
00397             /* Seek to the correct position */
00398             Position.LowPart = SectionHeader->PointerToRawData;
00399             Status = ArcSeek(FileId, &Position, SeekAbsolute);
00400 
00401             TRACE("SH->VA: 0x%X\n", SectionHeader->VirtualAddress);
00402 
00403             /* Read this section from the file, size = SizeOfRawData */
00404             Status = ArcRead(FileId, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress, SizeOfRawData, &BytesRead);
00405 
00406             if (Status != ESUCCESS)
00407             {
00408                 ERR("WinLdrLoadImage(): Error reading section from file!\n");
00409                 break;
00410             }
00411         }
00412 
00413         /* Size of data is less than the virtual size - fill up the remainder with zeroes */
00414         if (SizeOfRawData < VirtualSize)
00415         {
00416             TRACE("WinLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData, VirtualSize);
00417             RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG_PTR)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);
00418         }
00419 
00420         SectionHeader++;
00421     }
00422 
00423     /* We are done with the file - close it */
00424     ArcClose(FileId);
00425 
00426     /* If loading failed - return right now */
00427     if (Status != ESUCCESS)
00428         return FALSE;
00429 
00430 
00431     /* Relocate the image, if it needs it */
00432     if (NtHeaders->OptionalHeader.ImageBase != (ULONG_PTR)VirtualBase)
00433     {
00434         WARN("Relocating %p -> %p\n", NtHeaders->OptionalHeader.ImageBase,
00435              VirtualBase);
00436         return (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,
00437             (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,
00438             "FreeLdr",
00439             TRUE,
00440             TRUE, /* in case of conflict still return success */
00441             FALSE);
00442     }
00443 
00444     TRACE("WinLdrLoadImage() done, PA = %p\n", *ImageBasePA);
00445     return TRUE;
00446 }
00447 
00448 /* PRIVATE FUNCTIONS *******************************************************/
00449 
00450 /* DllName - physical, UnicodeString->Buffer - virtual */
00451 static BOOLEAN
00452 WinLdrpCompareDllName(IN PCH DllName,
00453                       IN PUNICODE_STRING UnicodeName)
00454 {
00455     PWSTR Buffer;
00456     UNICODE_STRING UnicodeNamePA;
00457     SIZE_T i, Length;
00458 
00459     /* First obvious check: for length of two names */
00460     Length = strlen(DllName);
00461 
00462     UnicodeNamePA.Length = UnicodeName->Length;
00463     UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;
00464     UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);
00465     TRACE("WinLdrpCompareDllName: %s and %wZ, Length = %d "
00466         "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length);
00467 
00468     if ((Length * sizeof(WCHAR)) > UnicodeName->Length)
00469         return FALSE;
00470 
00471     /* Store pointer to unicode string's buffer */
00472     Buffer = VaToPa(UnicodeName->Buffer);
00473 
00474     /* Loop character by character */
00475     for (i = 0; i < Length; i++)
00476     {
00477         /* Compare two characters, uppercasing them */
00478         if (toupper(*DllName) != toupper((CHAR)*Buffer))
00479             return FALSE;
00480 
00481         /* Move to the next character */
00482         DllName++;
00483         Buffer++;
00484     }
00485 
00486     /* Check, if strings either fully match, or match till the "." (w/o extension) */
00487     if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))
00488     {
00489         /* Yes they do */
00490         return TRUE;
00491     }
00492 
00493     /* Strings don't match, return FALSE */
00494     return FALSE;
00495 }
00496 
00497 static BOOLEAN
00498 WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead,
00499                       IN PVOID DllBase,
00500                       IN PVOID ImageBase,
00501                       IN PIMAGE_THUNK_DATA ThunkData,
00502                       IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
00503                       IN ULONG ExportSize,
00504                       IN BOOLEAN ProcessForwards)
00505 {
00506     ULONG Ordinal;
00507     PULONG NameTable, FunctionTable;
00508     PUSHORT OrdinalTable;
00509     LONG High, Low, Middle, Result;
00510     ULONG Hint;
00511     PIMAGE_IMPORT_BY_NAME ImportData;
00512     PCHAR ExportName;
00513 
00514     //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
00515     //  DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
00516 
00517     /* Check passed DllBase param */
00518     if(DllBase == NULL)
00519     {
00520         WARN("DllBase == NULL!\n");
00521         return FALSE;
00522     }
00523 
00524     /* Convert all non-critical pointers to PA from VA */
00525     ThunkData = VaToPa(ThunkData);
00526 
00527     /* Is the reference by ordinal? */
00528     if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
00529     {
00530         /* Yes, calculate the ordinal */
00531         Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
00532         //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
00533     }
00534     else
00535     {
00536         /* It's reference by name, we have to look it up in the export directory */
00537         if (!ProcessForwards)
00538         {
00539             /* AddressOfData in thunk entry will become a virtual address (from relative) */
00540             //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
00541             ThunkData->u1.AddressOfData =
00542                 (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData);
00543             //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
00544         }
00545 
00546         /* Get the import name */
00547         ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData);
00548 
00549         /* Get pointers to Name and Ordinal tables (RVA -> VA) */
00550         NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
00551         OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));
00552 
00553         //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
00554         //  NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
00555 
00556         /* Get the hint, convert it to a physical pointer */
00557         Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;
00558         //TRACE("HintIndex %d\n", Hint);
00559 
00560         /* Get the export name from the hint */
00561         ExportName = VaToPa(RVA(DllBase, NameTable[Hint]));
00562 
00563         /* If Hint is less than total number of entries in the export directory,
00564            and import name == export name, then we can just get it from the OrdinalTable */
00565         if ((Hint < ExportDirectory->NumberOfNames) &&
00566             (strcmp(ExportName, (PCHAR)ImportData->Name) == 0))
00567         {
00568             Ordinal = OrdinalTable[Hint];
00569             //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
00570         }
00571         else
00572         {
00573             /* It's not the easy way, we have to lookup import name in the name table.
00574                Let's use a binary search for this task. */
00575 
00576             //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n");
00577 
00578             /* Low boundary is set to 0, and high boundary to the maximum index */
00579             Low = 0;
00580             High = ExportDirectory->NumberOfNames - 1;
00581 
00582             /* Perform a binary-search loop */
00583             while (High >= Low)
00584             {
00585                 /* Divide by 2 by shifting to the right once */
00586                 Middle = (Low + High) / 2;
00587 
00588                 /* Get the name from the name table */
00589                 ExportName = VaToPa(RVA(DllBase, NameTable[Middle]));
00590 
00591                 /* Compare the names */
00592                 Result = strcmp(ExportName, (PCHAR)ImportData->Name);
00593 
00594                 /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/
00595                     /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
00596                     /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/
00597 
00598                 /*TRACE("TE->u1.AOD %p, fulladdr %p\n",
00599                     ThunkData->u1.AddressOfData,
00600                     ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/
00601 
00602 
00603                 /* Depending on result of strcmp, perform different actions */
00604                 if (Result > 0)
00605                 {
00606                     /* Adjust top boundary */
00607                     High = Middle - 1;
00608                 }
00609                 else if (Result < 0)
00610                 {
00611                     /* Adjust bottom boundary */
00612                     Low = Middle + 1;
00613                 }
00614                 else
00615                 {
00616                     /* Yay, found it! */
00617                     break;
00618                 }
00619             }
00620 
00621             /* If high boundary is less than low boundary, then no result found */
00622             if (High < Low)
00623             {
00624                 //Print(L"Error in binary search\n");
00625                 ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name);
00626                 return FALSE;
00627             }
00628 
00629             /* Everything allright, get the ordinal */
00630             Ordinal = OrdinalTable[Middle];
00631 
00632             //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal);
00633         }
00634     }
00635 
00636     /* Check ordinal number for validity! */
00637     if (Ordinal >= ExportDirectory->NumberOfFunctions)
00638     {
00639         ERR("Ordinal number is invalid!\n");
00640         return FALSE;
00641     }
00642 
00643     /* Get a pointer to the function table */
00644     FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));
00645 
00646     /* Save a pointer to the function */
00647     ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]);
00648 
00649     /* Is it a forwarder? (function pointer isn't within the export directory) */
00650     if (((ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function) > (ULONG_PTR)ExportDirectory) &&
00651         ((ULONG_PTR)VaToPa((PVOID)ThunkData->u1.Function) < ((ULONG_PTR)ExportDirectory + ExportSize)))
00652     {
00653         PLDR_DATA_TABLE_ENTRY DataTableEntry;
00654         CHAR ForwardDllName[255];
00655         PIMAGE_EXPORT_DIRECTORY RefExportDirectory;
00656         ULONG RefExportSize;
00657 
00658         /* Save the name of the forward dll */
00659         RtlCopyMemory(ForwardDllName, (PCHAR)VaToPa((PVOID)ThunkData->u1.Function), sizeof(ForwardDllName));
00660 
00661         /* Strip out its extension */
00662         *strchr(ForwardDllName,'.') = '\0';
00663 
00664         TRACE("WinLdrpBindImportName(): ForwardDllName %s\n", ForwardDllName);
00665         if (!WinLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry))
00666         {
00667             /* We can't continue if DLL couldn't be loaded, so bomb out with an error */
00668             //Print(L"Error loading DLL!\n");
00669             ERR("Error loading DLL!\n");
00670             return FALSE;
00671         }
00672 
00673         /* Get pointer to the export directory of loaded DLL */
00674         RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
00675             RtlImageDirectoryEntryToData(VaToPa(DataTableEntry->DllBase),
00676             TRUE,
00677             IMAGE_DIRECTORY_ENTRY_EXPORT,
00678             &RefExportSize);
00679 
00680         /* Fail if it's NULL */
00681         if (RefExportDirectory)
00682         {
00683             UCHAR Buffer[128];
00684             IMAGE_THUNK_DATA RefThunkData;
00685             PIMAGE_IMPORT_BY_NAME ImportByName;
00686             PCHAR ImportName;
00687             BOOLEAN Status;
00688 
00689             /* Get pointer to the import name */
00690             ImportName = strchr((PCHAR)VaToPa((PVOID)ThunkData->u1.Function), '.') + 1;
00691 
00692             /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
00693             ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;
00694 
00695             /* Fill the name with the import name */
00696             RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);
00697 
00698             /* Set Hint to 0 */
00699             ImportByName->Hint = 0;
00700 
00701             /* And finally point ThunkData's AddressOfData to that structure */
00702             RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName;
00703 
00704             /* And recursively call ourselves */
00705             Status = WinLdrpBindImportName(
00706                 ModuleListHead,
00707                 DataTableEntry->DllBase,
00708                 ImageBase,
00709                 &RefThunkData,
00710                 RefExportDirectory,
00711                 RefExportSize,
00712                 TRUE);
00713 
00714             /* Fill out the ThunkData with data from RefThunkData */
00715             ThunkData->u1 = RefThunkData.u1;
00716 
00717             /* Return what we got from the recursive call */
00718             return Status;
00719         }
00720         else
00721         {
00722             /* Fail if ExportDirectory is NULL */
00723             return FALSE;
00724         }
00725     }
00726 
00727     /* Success! */
00728     return TRUE;
00729 }
00730 
00731 static BOOLEAN
00732 WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead,
00733                                 PCCH DirectoryPath,
00734                                 PCH ImportName,
00735                                 PLDR_DATA_TABLE_ENTRY *DataTableEntry)
00736 {
00737     CHAR FullDllName[256];
00738     BOOLEAN Status;
00739     PVOID BasePA;
00740 
00741     /* Prepare the full path to the file to be loaded */
00742     strcpy(FullDllName, DirectoryPath);
00743     strcat(FullDllName, ImportName);
00744 
00745     TRACE("Loading referenced DLL: %s\n", FullDllName);
00746     //Print(L"Loading referenced DLL: %s\n", FullDllName);
00747 
00748     /* Load the image */
00749     Status = WinLdrLoadImage(FullDllName, LoaderBootDriver, &BasePA);
00750 
00751     if (!Status)
00752     {
00753         ERR("WinLdrLoadImage() failed\n");
00754         return Status;
00755     }
00756 
00757     /* Allocate DTE for newly loaded DLL */
00758     Status = WinLdrAllocateDataTableEntry(ModuleListHead,
00759         ImportName,
00760         FullDllName,
00761         BasePA,
00762         DataTableEntry);
00763 
00764     if (!Status)
00765     {
00766         ERR("WinLdrAllocateDataTableEntry() failed with Status=0x%X\n", Status);
00767         return Status;
00768     }
00769 
00770     /* Scan its dependencies too */
00771     TRACE("WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
00772         VaToPa((*DataTableEntry)->BaseDllName.Buffer));
00773     Status = WinLdrScanImportDescriptorTable(ModuleListHead, DirectoryPath, *DataTableEntry);
00774 
00775     if (!Status)
00776     {
00777         ERR("WinLdrScanImportDescriptorTable() failed with Status=0x%X\n", Status);
00778         return Status;
00779     }
00780 
00781     return TRUE;
00782 }
00783 
00784 static BOOLEAN
00785 WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead,
00786                               IN PVOID DllBase,
00787                               IN PVOID ImageBase,
00788                               IN PIMAGE_THUNK_DATA ThunkData)
00789 {
00790     PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
00791     BOOLEAN Status;
00792     ULONG ExportSize;
00793 
00794     TRACE("WinLdrpScanImportAddressTable(): DllBase 0x%X, "
00795         "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData);
00796 
00797     /* Obtain the export table from the DLL's base */
00798     if (DllBase == NULL)
00799     {
00800         ERR("Error, DllBase == NULL!\n");
00801         return FALSE;
00802     }
00803     else
00804     {
00805         ExportDirectory =
00806             (PIMAGE_EXPORT_DIRECTORY)RtlImageDirectoryEntryToData(VaToPa(DllBase),
00807                 TRUE,
00808                 IMAGE_DIRECTORY_ENTRY_EXPORT,
00809                 &ExportSize);
00810     }
00811 
00812     TRACE("WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory);
00813 
00814     /* If pointer to Export Directory is */
00815     if (ExportDirectory == NULL)
00816     {
00817         ERR("DllBase=%p(%p)\n", DllBase, VaToPa(DllBase));
00818         return FALSE;
00819     }
00820 
00821     /* Go through each entry in the thunk table and bind it */
00822     while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)
00823     {
00824         /* Bind it */
00825         Status = WinLdrpBindImportName(
00826             ModuleListHead,
00827             DllBase,
00828             ImageBase,
00829             ThunkData,
00830             ExportDirectory,
00831             ExportSize,
00832             FALSE);
00833 
00834         /* Move to the next entry */
00835         ThunkData++;
00836 
00837         /* Return error if binding was unsuccessful */
00838         if (!Status)
00839             return Status;
00840     }
00841 
00842     /* Return success */
00843     return TRUE;
00844 }

Generated on Sat May 26 2012 04:18:05 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.