ReactOS  0.4.13-dev-99-g7e18b6d
peloader.c
Go to the documentation of this file.
1 /*
2  * PROJECT: FreeLoader
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: boot/freeldr/freeldr/windows/peloader.c
5  * PURPOSE: Provides routines for loading PE files.
6  * (Deprecated remark) To be merged with arch/i386/loader.c in future.
7  *
8  * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
9  *
10  * The source code in this file is based on the work of respective
11  * authors of PE loading code in ReactOS and Brian Palmer and
12  * Alex Ionescu's arch/i386/loader.c, and my research project
13  * (creating a native EFI loader for Windows).
14  *
15  * NOTE: This article was very handy during development:
16  * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
17  */
18 
19 /* INCLUDES ***************************************************************/
20 #include <freeldr.h>
21 #include <debug.h>
22 
23 DBG_DEFAULT_CHANNEL(PELOADER);
24 
25 static BOOLEAN
28 
29 static BOOLEAN
31  IN PVOID DllBase,
32  IN PVOID ImageBase,
33  IN PIMAGE_THUNK_DATA ThunkData,
34  IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
35  IN ULONG ExportSize,
36  IN BOOLEAN ProcessForwards,
37  IN PCSTR DirectoryPath);
38 
39 static BOOLEAN
41  PCCH DirectoryPath,
42  PCH ImportName,
43  PLDR_DATA_TABLE_ENTRY *DataTableEntry);
44 
45 static BOOLEAN
47  IN PVOID DllBase,
48  IN PVOID ImageBase,
49  IN PIMAGE_THUNK_DATA ThunkData,
50  IN PCSTR DirectoryPath);
51 
52 
53 
54 /* FUNCTIONS **************************************************************/
55 
56 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
57 BOOLEAN
59  IN PCH DllName,
60  OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
61 {
62  PLDR_DATA_TABLE_ENTRY DataTableEntry;
63  LIST_ENTRY *ModuleEntry;
64 
65  TRACE("WinLdrCheckForLoadedDll: DllName %s\n", DllName);
66 
67  /* Just go through each entry in the LoadOrderList and compare loaded module's
68  name with a given name */
69  ModuleEntry = ModuleListHead->Flink;
70  while (ModuleEntry != ModuleListHead)
71  {
72  /* Get pointer to the current DTE */
73  DataTableEntry = CONTAINING_RECORD(ModuleEntry,
75  InLoadOrderLinks);
76 
77  TRACE("WinLdrCheckForLoadedDll: DTE %p, EP %p, base %p name '%.*ws'\n",
78  DataTableEntry, DataTableEntry->EntryPoint, DataTableEntry->DllBase,
79  DataTableEntry->BaseDllName.Length / 2, VaToPa(DataTableEntry->BaseDllName.Buffer));
80 
81  /* Compare names */
82  if (WinLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))
83  {
84  /* Yes, found it, report pointer to the loaded module's DTE
85  to the caller and increase load count for it */
86  *LoadedEntry = DataTableEntry;
87  DataTableEntry->LoadCount++;
88  TRACE("WinLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry);
89  return TRUE;
90  }
91 
92  /* Go to the next entry */
93  ModuleEntry = ModuleEntry->Flink;
94  }
95 
96  /* Nothing found */
97  return FALSE;
98 }
99 
100 BOOLEAN
102  IN PCCH DirectoryPath,
103  IN PLDR_DATA_TABLE_ENTRY ScanDTE)
104 {
105  PLDR_DATA_TABLE_ENTRY DataTableEntry;
106  PIMAGE_IMPORT_DESCRIPTOR ImportTable;
107  ULONG ImportTableSize;
108  PCH ImportName;
110 
111  /* Get a pointer to the import table of this image */
112  ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),
113  TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
114 
115  {
116  UNICODE_STRING BaseName;
117  BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer);
118  BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength;
119  BaseName.Length = ScanDTE->BaseDllName.Length;
120  TRACE("WinLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
121  &BaseName, ImportTable);
122  }
123 
124  /* If image doesn't have any import directory - just return success */
125  if (ImportTable == NULL)
126  return TRUE;
127 
128  /* Loop through all entries */
129  for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
130  {
131  /* Get pointer to the name */
132  ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
133  TRACE("WinLdrScanImportDescriptorTable(): Looking at %s\n", ImportName);
134 
135  /* In case we get a reference to ourselves - just skip it */
136  if (WinLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))
137  continue;
138 
139  /* Load the DLL if it is not already loaded */
140  if (!WinLdrCheckForLoadedDll(ModuleListHead, ImportName, &DataTableEntry))
141  {
143  DirectoryPath,
144  ImportName,
145  &DataTableEntry);
146  if (!Success)
147  {
148  ERR("WinLdrpLoadAndScanReferencedDll() failed\n");
149  return Success;
150  }
151  }
152 
153  /* Scan its import address table */
155  DataTableEntry->DllBase,
156  ScanDTE->DllBase,
157  (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk),
158  DirectoryPath);
159 
160  if (!Success)
161  {
162  ERR("WinLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n",
163  ImportName, DirectoryPath);
164  return Success;
165  }
166  }
167 
168  return TRUE;
169 }
170 
171 BOOLEAN
173  IN PCCH BaseDllName,
175  IN PVOID BasePA,
176  OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
177 {
178  PVOID BaseVA = PaToVa(BasePA);
179  PWSTR Buffer;
180  PLDR_DATA_TABLE_ENTRY DataTableEntry;
181  PIMAGE_NT_HEADERS NtHeaders;
182  USHORT Length;
183  TRACE("WinLdrAllocateDataTableEntry(, '%s', '%s', %p)\n",
184  BaseDllName, FullDllName, BasePA);
185 
186  /* Allocate memory for a data table entry, zero-initialize it */
188  TAG_WLDR_DTE);
189  if (DataTableEntry == NULL)
190  return FALSE;
191  RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));
192 
193  /* Get NT headers from the image */
194  NtHeaders = RtlImageNtHeader(BasePA);
195 
196  /* Initialize corresponding fields of DTE based on NT headers value */
197  DataTableEntry->DllBase = BaseVA;
198  DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
199  DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);
200  DataTableEntry->SectionPointer = 0;
201  DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
202 
203  /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
204  by simple conversion - copying each character */
205  Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
207  if (Buffer == NULL)
208  {
209  FrLdrHeapFree(DataTableEntry, TAG_WLDR_DTE);
210  return FALSE;
211  }
213 
214  DataTableEntry->BaseDllName.Length = Length;
215  DataTableEntry->BaseDllName.MaximumLength = Length;
216  DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);
217  while (*BaseDllName != 0)
218  {
219  *Buffer++ = *BaseDllName++;
220  }
221 
222  /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
223  using the same method */
224  Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
226  if (Buffer == NULL)
227  {
228  FrLdrHeapFree(DataTableEntry, TAG_WLDR_DTE);
229  return FALSE;
230  }
232 
233  DataTableEntry->FullDllName.Length = Length;
234  DataTableEntry->FullDllName.MaximumLength = Length;
235  DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);
236  while (*FullDllName != 0)
237  {
238  *Buffer++ = *FullDllName++;
239  }
240 
241  /* Initialize what's left - LoadCount which is 1, and set Flags so that
242  we know this entry is processed */
243  DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
244  DataTableEntry->LoadCount = 1;
245 
246  /* Insert this DTE to a list in the LPB */
248  TRACE("Inserting DTE %p, name='%.*S' DllBase=%p \n", DataTableEntry,
249  DataTableEntry->BaseDllName.Length / 2,
250  VaToPa(DataTableEntry->BaseDllName.Buffer),
251  DataTableEntry->DllBase);
252 
253  /* Save pointer to a newly allocated and initialized entry */
254  *NewEntry = DataTableEntry;
255 
256  /* Return success */
257  return TRUE;
258 }
259 
260 /*
261  * WinLdrLoadImage loads the specified image from the file (it doesn't
262  * perform any additional operations on the filename, just directly
263  * calls the file I/O routines), and relocates it so that it's ready
264  * to be used when paging is enabled.
265  * Addressing mode: physical
266  */
267 BOOLEAN
269  TYPE_OF_MEMORY MemoryType,
270  OUT PVOID *ImageBasePA)
271 {
272  ULONG FileId;
273  PVOID PhysicalBase;
274  PVOID VirtualBase = NULL;
275  UCHAR HeadersBuffer[SECTOR_SIZE * 2];
276  PIMAGE_NT_HEADERS NtHeaders;
277  PIMAGE_SECTION_HEADER SectionHeader;
278  ULONG VirtualSize, SizeOfRawData, NumberOfSections;
281  ULONG i, BytesRead;
282  TRACE("WinLdrLoadImage(%s, %ld, *)\n", FileName, MemoryType);
283 
284  /* Open the image file */
285  Status = ArcOpen(FileName, OpenReadOnly, &FileId);
286  if (Status != ESUCCESS)
287  {
288  // UiMessageBox("Can not open the file.");
289  return FALSE;
290  }
291 
292  /* Load the first 2 sectors of the image so we can read the PE header */
293  Status = ArcRead(FileId, HeadersBuffer, SECTOR_SIZE * 2, &BytesRead);
294  if (Status != ESUCCESS)
295  {
296  UiMessageBox("Error reading from file.");
297  ArcClose(FileId);
298  return FALSE;
299  }
300 
301  /* Now read the MZ header to get the offset to the PE Header */
302  NtHeaders = RtlImageNtHeader(HeadersBuffer);
303  if (!NtHeaders)
304  {
305  // Print(L"Error - no NT header found in %s\n", FileName);
306  UiMessageBox("Error - no NT header found.");
307  ArcClose(FileId);
308  return FALSE;
309  }
310 
311  /* Ensure this is executable image */
312  if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
313  {
314  // Print(L"Not an executable image %s\n", FileName);
315  UiMessageBox("Not an executable image.");
316  ArcClose(FileId);
317  return FALSE;
318  }
319 
320  /* Store number of sections to read and a pointer to the first section */
321  NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
322  SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
323 
324  /* Try to allocate this memory, if fails - allocate somewhere else */
325  PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
326  (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
327  MemoryType);
328 
329  if (PhysicalBase == NULL)
330  {
331  /* It's ok, we don't panic - let's allocate again at any other "low" place */
332  PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
333 
334  if (PhysicalBase == NULL)
335  {
336  // Print(L"Failed to alloc pages for image %s\n", FileName);
337  UiMessageBox("Failed to alloc pages for image.");
338  ArcClose(FileId);
339  return FALSE;
340  }
341  }
342 
343  /* This is the real image base - in form of a virtual address */
344  VirtualBase = PaToVa(PhysicalBase);
345 
346  TRACE("Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase);
347 
348  /* Set to 0 position and fully load the file image */
349  Position.HighPart = Position.LowPart = 0;
350  Status = ArcSeek(FileId, &Position, SeekAbsolute);
351  if (Status != ESUCCESS)
352  {
353  UiMessageBox("Error seeking to start of file.");
354  ArcClose(FileId);
355  return FALSE;
356  }
357 
358  Status = ArcRead(FileId, PhysicalBase, NtHeaders->OptionalHeader.SizeOfHeaders, &BytesRead);
359  if (Status != ESUCCESS)
360  {
361  // Print(L"Error reading headers %s\n", FileName);
362  UiMessageBox("Error reading headers.");
363  ArcClose(FileId);
364  return FALSE;
365  }
366 
367  /* Reload the NT Header */
368  NtHeaders = RtlImageNtHeader(PhysicalBase);
369 
370  /* Load the first section */
371  SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
372 
373  /* Fill output parameters */
374  *ImageBasePA = PhysicalBase;
375 
376  /* Walk through each section and read it (check/fix any possible
377  bad situations, if they arise) */
378  for (i = 0; i < NumberOfSections; i++)
379  {
380  VirtualSize = SectionHeader->Misc.VirtualSize;
381  SizeOfRawData = SectionHeader->SizeOfRawData;
382 
383  /* Handle a case when VirtualSize equals 0 */
384  if (VirtualSize == 0)
385  VirtualSize = SizeOfRawData;
386 
387  /* If PointerToRawData is 0, then force its size to be also 0 */
388  if (SectionHeader->PointerToRawData == 0)
389  {
390  SizeOfRawData = 0;
391  }
392  else
393  {
394  /* Cut the loaded size to the VirtualSize extents */
395  if (SizeOfRawData > VirtualSize)
396  SizeOfRawData = VirtualSize;
397  }
398 
399  /* Actually read the section (if its size is not 0) */
400  if (SizeOfRawData != 0)
401  {
402  /* Seek to the correct position */
403  Position.LowPart = SectionHeader->PointerToRawData;
404  Status = ArcSeek(FileId, &Position, SeekAbsolute);
405 
406  TRACE("SH->VA: 0x%X\n", SectionHeader->VirtualAddress);
407 
408  /* Read this section from the file, size = SizeOfRawData */
409  Status = ArcRead(FileId, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress, SizeOfRawData, &BytesRead);
410  if (Status != ESUCCESS)
411  {
412  ERR("WinLdrLoadImage(): Error reading section from file!\n");
413  break;
414  }
415  }
416 
417  /* Size of data is less than the virtual size - fill up the remainder with zeroes */
418  if (SizeOfRawData < VirtualSize)
419  {
420  TRACE("WinLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData, VirtualSize);
421  RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG_PTR)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);
422  }
423 
424  SectionHeader++;
425  }
426 
427  /* We are done with the file - close it */
428  ArcClose(FileId);
429 
430  /* If loading failed - return right now */
431  if (Status != ESUCCESS)
432  return FALSE;
433 
434  /* Relocate the image, if it needs it */
435  if (NtHeaders->OptionalHeader.ImageBase != (ULONG_PTR)VirtualBase)
436  {
437  WARN("Relocating %p -> %p\n", NtHeaders->OptionalHeader.ImageBase,
438  VirtualBase);
439  return (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,
440  (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,
441  "FreeLdr",
442  TRUE,
443  TRUE, /* in case of conflict still return success */
444  FALSE);
445  }
446 
447  TRACE("WinLdrLoadImage() done, PA = %p\n", *ImageBasePA);
448  return TRUE;
449 }
450 
451 /* PRIVATE FUNCTIONS *******************************************************/
452 
453 /* DllName - physical, UnicodeString->Buffer - virtual */
454 static BOOLEAN
457 {
458  PWSTR Buffer;
459  UNICODE_STRING UnicodeNamePA;
460  SIZE_T i, Length;
461 
462  /* First obvious check: for length of two names */
463  Length = strlen(DllName);
464 
465  UnicodeNamePA.Length = UnicodeName->Length;
466  UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;
467  UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);
468  TRACE("WinLdrpCompareDllName: %s and %wZ, Length = %d "
469  "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length);
470 
471  if ((Length * sizeof(WCHAR)) > UnicodeName->Length)
472  return FALSE;
473 
474  /* Store pointer to unicode string's buffer */
475  Buffer = VaToPa(UnicodeName->Buffer);
476 
477  /* Loop character by character */
478  for (i = 0; i < Length; i++)
479  {
480  /* Compare two characters, uppercasing them */
481  if (toupper(*DllName) != toupper((CHAR)*Buffer))
482  return FALSE;
483 
484  /* Move to the next character */
485  DllName++;
486  Buffer++;
487  }
488 
489  /* Check, if strings either fully match, or match till the "." (w/o extension) */
490  if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))
491  {
492  /* Yes they do */
493  return TRUE;
494  }
495 
496  /* Strings don't match, return FALSE */
497  return FALSE;
498 }
499 
500 static BOOLEAN
502  IN PVOID DllBase,
503  IN PVOID ImageBase,
504  IN PIMAGE_THUNK_DATA ThunkData,
505  IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
506  IN ULONG ExportSize,
507  IN BOOLEAN ProcessForwards,
508  IN PCSTR DirectoryPath)
509 {
510  ULONG Ordinal;
511  PULONG NameTable, FunctionTable;
512  PUSHORT OrdinalTable;
513  LONG High, Low, Middle, Result;
514  ULONG Hint;
515  PIMAGE_IMPORT_BY_NAME ImportData;
516  PCHAR ExportName, ForwarderName;
518 
519  //TRACE("WinLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
520  // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
521 
522  /* Check passed DllBase param */
523  if(DllBase == NULL)
524  {
525  WARN("DllBase == NULL!\n");
526  return FALSE;
527  }
528 
529  /* Convert all non-critical pointers to PA from VA */
530  ThunkData = VaToPa(ThunkData);
531 
532  /* Is the reference by ordinal? */
533  if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
534  {
535  /* Yes, calculate the ordinal */
536  Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
537  //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
538  }
539  else
540  {
541  /* It's reference by name, we have to look it up in the export directory */
542  if (!ProcessForwards)
543  {
544  /* AddressOfData in thunk entry will become a virtual address (from relative) */
545  //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
546  ThunkData->u1.AddressOfData =
547  (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData);
548  //TRACE("WinLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
549  }
550 
551  /* Get the import name */
552  ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData);
553 
554  /* Get pointers to Name and Ordinal tables (RVA -> VA) */
555  NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
556  OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));
557 
558  //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
559  // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
560 
561  /* Get the hint, convert it to a physical pointer */
562  Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;
563  //TRACE("HintIndex %d\n", Hint);
564 
565  /* Get the export name from the hint */
566  ExportName = VaToPa(RVA(DllBase, NameTable[Hint]));
567 
568  /* If Hint is less than total number of entries in the export directory,
569  and import name == export name, then we can just get it from the OrdinalTable */
570  if ((Hint < ExportDirectory->NumberOfNames) &&
571  (strcmp(ExportName, (PCHAR)ImportData->Name) == 0))
572  {
573  Ordinal = OrdinalTable[Hint];
574  //TRACE("WinLdrpBindImportName(): Ordinal %d\n", Ordinal);
575  }
576  else
577  {
578  /* It's not the easy way, we have to lookup import name in the name table.
579  Let's use a binary search for this task. */
580 
581  //TRACE("WinLdrpBindImportName() looking up the import name using binary search...\n");
582 
583  /* Low boundary is set to 0, and high boundary to the maximum index */
584  Low = 0;
585  High = ExportDirectory->NumberOfNames - 1;
586 
587  /* Perform a binary-search loop */
588  while (High >= Low)
589  {
590  /* Divide by 2 by shifting to the right once */
591  Middle = (Low + High) / 2;
592 
593  /* Get the name from the name table */
594  ExportName = VaToPa(RVA(DllBase, NameTable[Middle]));
595 
596  /* Compare the names */
597  Result = strcmp(ExportName, (PCHAR)ImportData->Name);
598 
599  /*TRACE("Binary search: comparing Import '__', Export '%s'\n",*/
600  /*VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),*/
601  /*(PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));*/
602 
603  /*TRACE("TE->u1.AOD %p, fulladdr %p\n",
604  ThunkData->u1.AddressOfData,
605  ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );*/
606 
607 
608  /* Depending on result of strcmp, perform different actions */
609  if (Result > 0)
610  {
611  /* Adjust top boundary */
612  High = Middle - 1;
613  }
614  else if (Result < 0)
615  {
616  /* Adjust bottom boundary */
617  Low = Middle + 1;
618  }
619  else
620  {
621  /* Yay, found it! */
622  break;
623  }
624  }
625 
626  /* If high boundary is less than low boundary, then no result found */
627  if (High < Low)
628  {
629  //Print(L"Error in binary search\n");
630  ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name);
631  return FALSE;
632  }
633 
634  /* Everything alright, get the ordinal */
635  Ordinal = OrdinalTable[Middle];
636 
637  //TRACE("WinLdrpBindImportName() found Ordinal %d\n", Ordinal);
638  }
639  }
640 
641  /* Check ordinal number for validity! */
642  if (Ordinal >= ExportDirectory->NumberOfFunctions)
643  {
644  ERR("Ordinal number is invalid!\n");
645  return FALSE;
646  }
647 
648  /* Get a pointer to the function table */
649  FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));
650 
651  /* Save a pointer to the function */
652  ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]);
653 
654  /* Is it a forwarder? (function pointer is within the export directory) */
655  ForwarderName = (PCHAR)VaToPa((PVOID)ThunkData->u1.Function);
656  if (((ULONG_PTR)ForwarderName > (ULONG_PTR)ExportDirectory) &&
657  ((ULONG_PTR)ForwarderName < ((ULONG_PTR)ExportDirectory + ExportSize)))
658  {
659  PLDR_DATA_TABLE_ENTRY DataTableEntry;
660  CHAR ForwardDllName[255];
661  PIMAGE_EXPORT_DIRECTORY RefExportDirectory;
662  ULONG RefExportSize;
663  TRACE("WinLdrpBindImportName(): ForwarderName %s\n", ForwarderName);
664 
665  /* Save the name of the forward dll */
666  RtlCopyMemory(ForwardDllName, ForwarderName, sizeof(ForwardDllName));
667 
668  /* Strip out the symbol name */
669  *strrchr(ForwardDllName,'.') = '\0';
670 
671  /* Check if the target image is already loaded */
672  if (!WinLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry))
673  {
674  /* Check if the forward dll name has an extension */
675  if (strchr(ForwardDllName, '.') == NULL)
676  {
677  /* Name does not have an extension, append '.dll' */
678  strcat(ForwardDllName, ".dll");
679  }
680 
681  /* Now let's try to load it! */
683  DirectoryPath,
684  ForwardDllName,
685  &DataTableEntry);
686  if (!Success)
687  {
688  ERR("WinLdrpLoadAndScanReferencedDll() failed to load forwarder dll.\n");
689  return Success;
690  }
691  }
692 
693  /* Get pointer to the export directory of loaded DLL */
694  RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
696  TRUE,
698  &RefExportSize);
699 
700  /* Fail if it's NULL */
701  if (RefExportDirectory)
702  {
703  UCHAR Buffer[128];
704  IMAGE_THUNK_DATA RefThunkData;
705  PIMAGE_IMPORT_BY_NAME ImportByName;
706  PCHAR ImportName;
707 
708  /* Get pointer to the import name */
709  ImportName = strrchr(ForwarderName, '.') + 1;
710 
711  /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
712  ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;
713 
714  /* Fill the name with the import name */
715  RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);
716 
717  /* Set Hint to 0 */
718  ImportByName->Hint = 0;
719 
720  /* And finally point ThunkData's AddressOfData to that structure */
721  RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName;
722 
723  /* And recursively call ourselves */
725  DataTableEntry->DllBase,
726  ImageBase,
727  &RefThunkData,
728  RefExportDirectory,
729  RefExportSize,
730  TRUE,
731  DirectoryPath);
732 
733  /* Fill out the ThunkData with data from RefThunkData */
734  ThunkData->u1 = RefThunkData.u1;
735 
736  /* Return what we got from the recursive call */
737  return Success;
738  }
739  else
740  {
741  /* Fail if ExportDirectory is NULL */
742  return FALSE;
743  }
744  }
745 
746  /* Success! */
747  return TRUE;
748 }
749 
750 static BOOLEAN
752  PCCH DirectoryPath,
753  PCH ImportName,
754  PLDR_DATA_TABLE_ENTRY *DataTableEntry)
755 {
756  CHAR FullDllName[256];
758  PVOID BasePA = NULL;
759 
760  /* Prepare the full path to the file to be loaded */
761  strcpy(FullDllName, DirectoryPath);
762  strcat(FullDllName, ImportName);
763 
764  TRACE("Loading referenced DLL: %s\n", FullDllName);
765  //Print(L"Loading referenced DLL: %s\n", FullDllName);
766 
767  /* Load the image */
769  if (!Success)
770  {
771  ERR("WinLdrLoadImage() failed\n");
772  return Success;
773  }
774 
775  /* Allocate DTE for newly loaded DLL */
777  ImportName,
778  FullDllName,
779  BasePA,
780  DataTableEntry);
781  if (!Success)
782  {
783  ERR("WinLdrAllocateDataTableEntry() failed\n");
784  return Success;
785  }
786 
787  /* Scan its dependencies too */
788  TRACE("WinLdrScanImportDescriptorTable() calling ourselves for %S\n",
789  VaToPa((*DataTableEntry)->BaseDllName.Buffer));
790  Success = WinLdrScanImportDescriptorTable(ModuleListHead, DirectoryPath, *DataTableEntry);
791  if (!Success)
792  {
793  ERR("WinLdrScanImportDescriptorTable() failed\n");
794  return Success;
795  }
796 
797  return TRUE;
798 }
799 
800 static BOOLEAN
802  IN PVOID DllBase,
803  IN PVOID ImageBase,
804  IN PIMAGE_THUNK_DATA ThunkData,
805  IN PCSTR DirectoryPath)
806 {
807  PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
809  ULONG ExportSize;
810 
811  TRACE("WinLdrpScanImportAddressTable(): DllBase 0x%X, "
812  "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData);
813 
814  /* Obtain the export table from the DLL's base */
815  if (DllBase == NULL)
816  {
817  ERR("Error, DllBase == NULL!\n");
818  return FALSE;
819  }
820  else
821  {
822  ExportDirectory =
824  TRUE,
826  &ExportSize);
827  }
828 
829  TRACE("WinLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory);
830 
831  /* If pointer to Export Directory is */
832  if (ExportDirectory == NULL)
833  {
834  ERR("DllBase=%p(%p)\n", DllBase, VaToPa(DllBase));
835  return FALSE;
836  }
837 
838  /* Go through each entry in the thunk table and bind it */
839  while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)
840  {
841  /* Bind it */
843  DllBase,
844  ImageBase,
845  ThunkData,
846  ExportDirectory,
847  ExportSize,
848  FALSE,
849  DirectoryPath);
850 
851  /* Move to the next entry */
852  ThunkData++;
853 
854  /* Return error if binding was unsuccessful */
855  if (!Success)
856  return Success;
857  }
858 
859  /* Return success */
860  return TRUE;
861 }
signed char * PCHAR
Definition: retypes.h:7
#define LDRP_ENTRY_PROCESSED
Definition: ldrtypes.h:43
#define IN
Definition: typedefs.h:38
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
FORCEINLINE VOID FrLdrHeapFree(PVOID MemoryPointer, ULONG Tag)
Definition: mm.h:170
static BOOLEAN WinLdrpCompareDllName(IN PCH DllName, IN PUNICODE_STRING UnicodeName)
Definition: peloader.c:455
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
USHORT MaximumLength
Definition: env_spec_w32.h:370
Definition: arc.h:32
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
BOOLEAN WinLdrAllocateDataTableEntry(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH BaseDllName, IN PCCH FullDllName, IN PVOID BasePA, OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
Definition: peloader.c:172
uint16_t * PWSTR
Definition: typedefs.h:54
static COORD Position
Definition: mouse.c:34
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
#define WARN(fmt,...)
Definition: debug.h:111
IN PDCB IN POEM_STRING IN PUNICODE_STRING UnicodeName
Definition: fatprocs.h:1294
ULONG SizeOfImage
Definition: ldrtypes.h:142
static BOOLEAN WinLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead, IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkData, IN PCSTR DirectoryPath)
Definition: peloader.c:801
struct _IMAGE_IMPORT_DESCRIPTOR * PIMAGE_IMPORT_DESCRIPTOR
Definition: strmini.h:380
struct _IMAGE_IMPORT_BY_NAME * PIMAGE_IMPORT_BY_NAME
ULONG ARC_STATUS
Definition: arc.h:4
_Check_return_ _CRTIMP _CONST_RETURN char *__cdecl strrchr(_In_z_ const char *_Str, _In_ int _Ch)
GLdouble u1
Definition: glext.h:8308
#define InsertTailList(ListHead, Entry)
DWORD PointerToRawData
Definition: pedump.c:290
BOOLEAN WinLdrCheckForLoadedDll(IN OUT PLIST_ENTRY ModuleListHead, IN PCH DllName, OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
Definition: peloader.c:58
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
enum _TYPE_OF_MEMORY TYPE_OF_MEMORY
uint32_t ULONG_PTR
Definition: typedefs.h:63
PVOID DllBase
Definition: btrfs_drv.h:1805
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
unsigned int UINT32
#define IMAGE_FIRST_SECTION(NtHeader)
Definition: ntimage.h:427
#define SECTOR_SIZE
Definition: winldr.h:34
#define KSEG0_BASE
Definition: ketypes.h:273
long LONG
Definition: pedump.c:60
PVOID EntryPoint
Definition: ntddk_ex.h:203
CHAR * PCH
Definition: ntbasedef.h:398
union _IMAGE_SECTION_HEADER::@1519 Misc
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:347
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
Definition: bufpool.h:45
_In_ PCWSTR FullDllName
Definition: ldrtypes.h:246
BOOLEAN WinLdrLoadImage(IN PCHAR FileName, TYPE_OF_MEMORY MemoryType, OUT PVOID *ImageBasePA)
Definition: peloader.c:268
IMAGE_FILE_HEADER FileHeader
Definition: ntddk_ex.h:183
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define PCHAR
Definition: match.c:90
DBG_DEFAULT_CHANNEL(PELOADER)
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
CONST CHAR * PCCH
Definition: ntbasedef.h:399
int toupper(int c)
Definition: utclib.c:881
FORCEINLINE PVOID FrLdrHeapAlloc(SIZE_T MemorySize, ULONG Tag)
Definition: mm.h:163
#define TRACE(s)
Definition: solgame.cpp:4
__wchar_t WCHAR
Definition: xmlstorage.h:180
ULONG CheckSum
Definition: btrfs_drv.h:1811
#define IMAGE_FILE_EXECUTABLE_IMAGE
Definition: pedump.c:160
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
struct _LDR_DATA_TABLE_ENTRY * PLDR_DATA_TABLE_ENTRY
Definition: strmini.h:378
ARC_STATUS ArcRead(ULONG FileId, VOID *Buffer, ULONG N, ULONG *Count)
Definition: fs.c:237
unsigned char UCHAR
Definition: xmlstorage.h:181
static BOOLEAN WinLdrpBindImportName(IN OUT PLIST_ENTRY ModuleListHead, IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkData, IN PIMAGE_EXPORT_DIRECTORY ExportDirectory, IN ULONG ExportSize, IN BOOLEAN ProcessForwards, IN PCSTR DirectoryPath)
Definition: peloader.c:501
static const WCHAR L[]
Definition: oid.c:1250
#define RtlImageDirectoryEntryToData
Definition: compat.h:460
PVOID MmAllocateMemoryWithType(SIZE_T MemorySize, TYPE_OF_MEMORY MemoryType)
Definition: mm.c:31
ARC_STATUS ArcSeek(ULONG FileId, LARGE_INTEGER *Position, SEEKMODE SeekMode)
Definition: fs.c:244
Definition: btrfs_drv.h:1801
#define TAG_WLDR_NAME
Definition: winldr.h:28
Definition: typedefs.h:117
PVOID MmAllocateMemoryAtAddress(SIZE_T MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
Definition: mm.c:85
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: compat.h:140
BOOLEAN WinLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH DirectoryPath, IN PLDR_DATA_TABLE_ENTRY ScanDTE)
Definition: peloader.c:101
Status
Definition: gdiplustypes.h:24
LIST_ENTRY InLoadOrderLinks
Definition: ldrtypes.h:137
#define ERR(fmt,...)
Definition: debug.h:109
#define RVA(m, b)
Definition: freeldr.h:24
PVOID SectionPointer
Definition: ntddk_ex.h:213
ULONG_PTR SIZE_T
Definition: typedefs.h:78
NTSYSAPI ULONG NTAPI LdrRelocateImageWithBias(_In_ PVOID NewAddress, _In_ LONGLONG AdditionalBias, _In_ PCCH LoaderName, _In_ ULONG Success, _In_ ULONG Conflict, _In_ ULONG Invalid)
#define IMAGE_SNAP_BY_ORDINAL(Ordinal)
Definition: ntimage.h:567
unsigned short USHORT
Definition: pedump.c:61
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1807
UNICODE_STRING BaseDllName
Definition: ldrtypes.h:144
static BOOLEAN WinLdrpLoadAndScanReferencedDll(PLIST_ENTRY ModuleListHead, PCCH DirectoryPath, PCH ImportName, PLDR_DATA_TABLE_ENTRY *DataTableEntry)
Definition: peloader.c:751
#define TAG_WLDR_DTE
Definition: winldr.h:26
unsigned int * PULONG
Definition: retypes.h:1
struct _IMAGE_EXPORT_DIRECTORY * PIMAGE_EXPORT_DIRECTORY
char * strchr(const char *String, int ch)
Definition: utclib.c:501
ARC_STATUS ArcClose(ULONG FileId)
Definition: fs.c:219
#define RtlImageNtHeader
Definition: compat.h:457
#define IMAGE_DIRECTORY_ENTRY_IMPORT
Definition: pedump.c:260
DWORD RVA
Definition: compat.h:903
#define OUT
Definition: typedefs.h:39
FORCEINLINE PVOID PaToVa(PVOID Pa)
Definition: conversion.h:22
ULONG Flags
Definition: ntddk_ex.h:207
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
ARC_STATUS ArcOpen(CHAR *Path, OPENMODE OpenMode, ULONG *FileId)
Definition: fs.c:57
unsigned int ULONG
Definition: retypes.h:1
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define ULONG_PTR
Definition: config.h:101
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:736
FORCEINLINE PVOID VaToPa(PVOID Va)
Definition: conversion.h:15
const char * PCSTR
Definition: typedefs.h:51
#define IMAGE_ORDINAL(Ordinal)
Definition: pedump.c:337
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
LIST_ENTRY * ModuleListHead
Definition: kdpacket.c:23
unsigned short * PUSHORT
Definition: retypes.h:2
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
union _IMAGE_THUNK_DATA32::@2046 u1
USHORT LoadCount
Definition: ntddk_ex.h:208