ReactOS  0.4.14-dev-52-g6116262
peloader.c
Go to the documentation of this file.
1 /*
2  * PROJECT: FreeLoader
3  * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4  * PURPOSE: Provides routines for loading PE files.
5  * (Deprecated remark) To be merged with arch/i386/loader.c in future.
6  *
7  * COPYRIGHT: Copyright 1998-2003 Brian Palmer <brianp@sginet.com>
8  * Copyright 2006-2019 Aleksey Bragin <aleksey@reactos.org>
9  *
10  * NOTES: 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  * This article was very handy during development:
16  * http://msdn.microsoft.com/msdnmag/issues/02/03/PE2/
17  */
18 
19 /* INCLUDES ******************************************************************/
20 
21 #include <freeldr.h>
22 #include <debug.h>
23 
24 DBG_DEFAULT_CHANNEL(PELOADER);
25 
26 /* PRIVATE FUNCTIONS *********************************************************/
27 
28 /* DllName - physical, UnicodeString->Buffer - virtual */
29 static BOOLEAN
31  IN PCH DllName,
33 {
34  PWSTR Buffer;
35  SIZE_T i, Length;
36 
37  /* First obvious check: for length of two names */
38  Length = strlen(DllName);
39 
40 #if DBG
41  {
42  UNICODE_STRING UnicodeNamePA;
43  UnicodeNamePA.Length = UnicodeName->Length;
44  UnicodeNamePA.MaximumLength = UnicodeName->MaximumLength;
45  UnicodeNamePA.Buffer = VaToPa(UnicodeName->Buffer);
46  TRACE("PeLdrpCompareDllName: %s and %wZ, Length = %d "
47  "UN->Length %d\n", DllName, &UnicodeNamePA, Length, UnicodeName->Length);
48  }
49 #endif
50 
51  if ((Length * sizeof(WCHAR)) > UnicodeName->Length)
52  return FALSE;
53 
54  /* Store pointer to unicode string's buffer */
55  Buffer = VaToPa(UnicodeName->Buffer);
56 
57  /* Loop character by character */
58  for (i = 0; i < Length; i++)
59  {
60  /* Compare two characters, uppercasing them */
61  if (toupper(*DllName) != toupper((CHAR)*Buffer))
62  return FALSE;
63 
64  /* Move to the next character */
65  DllName++;
66  Buffer++;
67  }
68 
69  /* Check, if strings either fully match, or match till the "." (w/o extension) */
70  if ((UnicodeName->Length == Length * sizeof(WCHAR)) || (*Buffer == L'.'))
71  {
72  /* Yes they do */
73  return TRUE;
74  }
75 
76  /* Strings don't match, return FALSE */
77  return FALSE;
78 }
79 
80 static BOOLEAN
83  IN PCCH DirectoryPath,
84  IN PCH ImportName,
86  OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry);
87 
88 static BOOLEAN
91  IN PVOID DllBase,
92  IN PVOID ImageBase,
93  IN PIMAGE_THUNK_DATA ThunkData,
94  IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
95  IN ULONG ExportSize,
96  IN BOOLEAN ProcessForwards,
97  IN PCSTR DirectoryPath,
99 {
100  ULONG Ordinal;
101  PULONG NameTable, FunctionTable;
102  PUSHORT OrdinalTable;
103  LONG High, Low, Middle, Result;
104  ULONG Hint;
105  PIMAGE_IMPORT_BY_NAME ImportData;
106  PCHAR ExportName, ForwarderName;
108 
109  //TRACE("PeLdrpBindImportName(): DllBase 0x%X, ImageBase 0x%X, ThunkData 0x%X, ExportDirectory 0x%X, ExportSize %d, ProcessForwards 0x%X\n",
110  // DllBase, ImageBase, ThunkData, ExportDirectory, ExportSize, ProcessForwards);
111 
112  /* Check passed DllBase param */
113  if(DllBase == NULL)
114  {
115  WARN("DllBase == NULL!\n");
116  return FALSE;
117  }
118 
119  /* Convert all non-critical pointers to PA from VA */
120  ThunkData = VaToPa(ThunkData);
121 
122  /* Is the reference by ordinal? */
123  if (IMAGE_SNAP_BY_ORDINAL(ThunkData->u1.Ordinal) && !ProcessForwards)
124  {
125  /* Yes, calculate the ordinal */
126  Ordinal = (ULONG)(IMAGE_ORDINAL(ThunkData->u1.Ordinal) - (UINT32)ExportDirectory->Base);
127  //TRACE("PeLdrpBindImportName(): Ordinal %d\n", Ordinal);
128  }
129  else
130  {
131  /* It's reference by name, we have to look it up in the export directory */
132  if (!ProcessForwards)
133  {
134  /* AddressOfData in thunk entry will become a virtual address (from relative) */
135  //TRACE("PeLdrpBindImportName(): ThunkData->u1.AOD was %p\n", ThunkData->u1.AddressOfData);
136  ThunkData->u1.AddressOfData =
137  (ULONG_PTR)RVA(ImageBase, ThunkData->u1.AddressOfData);
138  //TRACE("PeLdrpBindImportName(): ThunkData->u1.AOD became %p\n", ThunkData->u1.AddressOfData);
139  }
140 
141  /* Get the import name */
142  ImportData = VaToPa((PVOID)ThunkData->u1.AddressOfData);
143 
144  /* Get pointers to Name and Ordinal tables (RVA -> VA) */
145  NameTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNames));
146  OrdinalTable = VaToPa(RVA(DllBase, ExportDirectory->AddressOfNameOrdinals));
147 
148  //TRACE("NameTable 0x%X, OrdinalTable 0x%X, ED->AddressOfNames 0x%X, ED->AOFO 0x%X\n",
149  // NameTable, OrdinalTable, ExportDirectory->AddressOfNames, ExportDirectory->AddressOfNameOrdinals);
150 
151  /* Get the hint, convert it to a physical pointer */
152  Hint = ((PIMAGE_IMPORT_BY_NAME)VaToPa((PVOID)ThunkData->u1.AddressOfData))->Hint;
153  //TRACE("HintIndex %d\n", Hint);
154 
155  /* Get the export name from the hint */
156  ExportName = VaToPa(RVA(DllBase, NameTable[Hint]));
157 
158  /* If Hint is less than total number of entries in the export directory,
159  and import name == export name, then we can just get it from the OrdinalTable */
160  if ((Hint < ExportDirectory->NumberOfNames) &&
161  (strcmp(ExportName, (PCHAR)ImportData->Name) == 0))
162  {
163  Ordinal = OrdinalTable[Hint];
164  //TRACE("PeLdrpBindImportName(): Ordinal %d\n", Ordinal);
165  }
166  else
167  {
168  /* It's not the easy way, we have to lookup import name in the name table.
169  Let's use a binary search for this task. */
170 
171  //TRACE("PeLdrpBindImportName() looking up the import name using binary search...\n");
172 
173  /* Low boundary is set to 0, and high boundary to the maximum index */
174  Low = 0;
175  High = ExportDirectory->NumberOfNames - 1;
176 
177  /* Perform a binary-search loop */
178  while (High >= Low)
179  {
180  /* Divide by 2 by shifting to the right once */
181  Middle = (Low + High) / 2;
182 
183  /* Get the name from the name table */
184  ExportName = VaToPa(RVA(DllBase, NameTable[Middle]));
185 
186  /* Compare the names */
187  Result = strcmp(ExportName, (PCHAR)ImportData->Name);
188 
189  // TRACE("Binary search: comparing Import '__', Export '%s'\n",
190  // VaToPa(&((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name[0]),
191  // (PCHAR)VaToPa(RVA(DllBase, NameTable[Middle])));
192 
193  // TRACE("TE->u1.AOD %p, fulladdr %p\n",
194  // ThunkData->u1.AddressOfData,
195  // ((PIMAGE_IMPORT_BY_NAME)VaToPa(ThunkData->u1.AddressOfData))->Name );
196 
197  /* Depending on result of strcmp, perform different actions */
198  if (Result > 0)
199  {
200  /* Adjust top boundary */
201  High = Middle - 1;
202  }
203  else if (Result < 0)
204  {
205  /* Adjust bottom boundary */
206  Low = Middle + 1;
207  }
208  else
209  {
210  /* Yay, found it! */
211  break;
212  }
213  }
214 
215  /* If high boundary is less than low boundary, then no result found */
216  if (High < Low)
217  {
218  ERR("Did not find export '%s'!\n", (PCHAR)ImportData->Name);
219  return FALSE;
220  }
221 
222  /* Everything alright, get the ordinal */
223  Ordinal = OrdinalTable[Middle];
224 
225  //TRACE("PeLdrpBindImportName() found Ordinal %d\n", Ordinal);
226  }
227  }
228 
229  /* Check ordinal number for validity! */
230  if (Ordinal >= ExportDirectory->NumberOfFunctions)
231  {
232  ERR("Ordinal number is invalid!\n");
233  return FALSE;
234  }
235 
236  /* Get a pointer to the function table */
237  FunctionTable = (PULONG)VaToPa(RVA(DllBase, ExportDirectory->AddressOfFunctions));
238 
239  /* Save a pointer to the function */
240  ThunkData->u1.Function = (ULONG_PTR)RVA(DllBase, FunctionTable[Ordinal]);
241 
242  /* Is it a forwarder? (function pointer is within the export directory) */
243  ForwarderName = (PCHAR)VaToPa((PVOID)ThunkData->u1.Function);
244  if (((ULONG_PTR)ForwarderName > (ULONG_PTR)ExportDirectory) &&
245  ((ULONG_PTR)ForwarderName < ((ULONG_PTR)ExportDirectory + ExportSize)))
246  {
247  PLDR_DATA_TABLE_ENTRY DataTableEntry;
248  CHAR ForwardDllName[255];
249  PIMAGE_EXPORT_DIRECTORY RefExportDirectory;
250  ULONG RefExportSize;
251 
252  TRACE("PeLdrpBindImportName(): ForwarderName %s\n", ForwarderName);
253 
254  /* Save the name of the forward dll */
255  RtlCopyMemory(ForwardDllName, ForwarderName, sizeof(ForwardDllName));
256 
257  /* Strip out the symbol name */
258  *strrchr(ForwardDllName,'.') = '\0';
259 
260  /* Check if the target image is already loaded */
261  if (!PeLdrCheckForLoadedDll(ModuleListHead, ForwardDllName, &DataTableEntry))
262  {
263  /* Check if the forward dll name has an extension */
264  if (strchr(ForwardDllName, '.') == NULL)
265  {
266  /* Name does not have an extension, append '.dll' */
267  strcat(ForwardDllName, ".dll");
268  }
269 
270  /* Now let's try to load it! */
272  DirectoryPath,
273  ForwardDllName,
274  Parent,
275  &DataTableEntry);
276  if (!Success)
277  {
278  ERR("PeLdrpLoadAndScanReferencedDll() failed to load forwarder dll.\n");
279  return Success;
280  }
281  }
282 
283  /* Get pointer to the export directory of loaded DLL */
284  RefExportDirectory = (PIMAGE_EXPORT_DIRECTORY)
286  TRUE,
288  &RefExportSize);
289 
290  /* Fail if it's NULL */
291  if (RefExportDirectory)
292  {
293  UCHAR Buffer[128];
294  IMAGE_THUNK_DATA RefThunkData;
295  PIMAGE_IMPORT_BY_NAME ImportByName;
296  PCHAR ImportName;
297 
298  /* Get pointer to the import name */
299  ImportName = strrchr(ForwarderName, '.') + 1;
300 
301  /* Create a IMAGE_IMPORT_BY_NAME structure, pointing to the local Buffer */
302  ImportByName = (PIMAGE_IMPORT_BY_NAME)Buffer;
303 
304  /* Fill the name with the import name */
305  RtlCopyMemory(ImportByName->Name, ImportName, strlen(ImportName)+1);
306 
307  /* Set Hint to 0 */
308  ImportByName->Hint = 0;
309 
310  /* And finally point ThunkData's AddressOfData to that structure */
311  RefThunkData.u1.AddressOfData = (ULONG_PTR)ImportByName;
312 
313  /* And recursively call ourselves */
315  DataTableEntry->DllBase,
316  ImageBase,
317  &RefThunkData,
318  RefExportDirectory,
319  RefExportSize,
320  TRUE,
321  DirectoryPath,
322  Parent);
323 
324  /* Fill out the ThunkData with data from RefThunkData */
325  ThunkData->u1 = RefThunkData.u1;
326 
327  /* Return what we got from the recursive call */
328  return Success;
329  }
330  else
331  {
332  /* Fail if ExportDirectory is NULL */
333  return FALSE;
334  }
335  }
336 
337  /* Success! */
338  return TRUE;
339 }
340 
341 static BOOLEAN
344  IN PCCH DirectoryPath,
345  IN PCH ImportName,
347  OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry)
348 {
349  CHAR FullDllName[256];
351  PVOID BasePA = NULL;
352 
353  /* Prepare the full path to the file to be loaded */
354  strcpy(FullDllName, DirectoryPath);
355  strcat(FullDllName, ImportName);
356 
357  TRACE("Loading referenced DLL: %s\n", FullDllName);
358 
359  /* Load the image */
361  if (!Success)
362  {
363  ERR("PeLdrLoadImage() failed\n");
364  return Success;
365  }
366 
367  /* Allocate DTE for newly loaded DLL */
369  ImportName,
370  FullDllName,
371  BasePA,
372  DataTableEntry);
373  if (!Success)
374  {
375  ERR("PeLdrAllocateDataTableEntry() failed\n");
376  return Success;
377  }
378 
379  (*DataTableEntry)->Flags |= LDRP_DRIVER_DEPENDENT_DLL;
380 
381  /* Scan its dependencies too */
382  TRACE("PeLdrScanImportDescriptorTable() calling ourselves for %S\n",
383  VaToPa((*DataTableEntry)->BaseDllName.Buffer));
384  Success = PeLdrScanImportDescriptorTable(ModuleListHead, DirectoryPath, *DataTableEntry);
385  if (!Success)
386  {
387  ERR("PeLdrScanImportDescriptorTable() failed\n");
388  return Success;
389  }
390 
391  return TRUE;
392 }
393 
394 static BOOLEAN
397  IN PVOID DllBase,
398  IN PVOID ImageBase,
399  IN PIMAGE_THUNK_DATA ThunkData,
400  IN PCSTR DirectoryPath,
402 {
403  PIMAGE_EXPORT_DIRECTORY ExportDirectory = NULL;
405  ULONG ExportSize;
406 
407  TRACE("PeLdrpScanImportAddressTable(): DllBase 0x%X, "
408  "ImageBase 0x%X, ThunkData 0x%X\n", DllBase, ImageBase, ThunkData);
409 
410  /* Obtain the export table from the DLL's base */
411  if (DllBase == NULL)
412  {
413  ERR("Error, DllBase == NULL!\n");
414  return FALSE;
415  }
416  else
417  {
418  ExportDirectory =
420  TRUE,
422  &ExportSize);
423  }
424 
425  TRACE("PeLdrpScanImportAddressTable(): ExportDirectory 0x%X\n", ExportDirectory);
426 
427  /* If pointer to Export Directory is */
428  if (ExportDirectory == NULL)
429  {
430  ERR("DllBase=%p(%p)\n", DllBase, VaToPa(DllBase));
431  return FALSE;
432  }
433 
434  /* Go through each entry in the thunk table and bind it */
435  while (((PIMAGE_THUNK_DATA)VaToPa(ThunkData))->u1.AddressOfData != 0)
436  {
437  /* Bind it */
439  DllBase,
440  ImageBase,
441  ThunkData,
442  ExportDirectory,
443  ExportSize,
444  FALSE,
445  DirectoryPath,
446  Parent);
447 
448  /* Move to the next entry */
449  ThunkData++;
450 
451  /* Return error if binding was unsuccessful */
452  if (!Success)
453  return Success;
454  }
455 
456  /* Return success */
457  return TRUE;
458 }
459 
460 
461 /* FUNCTIONS *****************************************************************/
462 
463 /* Returns TRUE if DLL has already been loaded - looks in LoadOrderList in LPB */
464 BOOLEAN
467  IN PCH DllName,
468  OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
469 {
470  PLDR_DATA_TABLE_ENTRY DataTableEntry;
471  LIST_ENTRY *ModuleEntry;
472 
473  TRACE("PeLdrCheckForLoadedDll: DllName %s\n", DllName);
474 
475  /* Just go through each entry in the LoadOrderList and compare loaded module's
476  name with a given name */
477  ModuleEntry = ModuleListHead->Flink;
478  while (ModuleEntry != ModuleListHead)
479  {
480  /* Get pointer to the current DTE */
481  DataTableEntry = CONTAINING_RECORD(ModuleEntry,
483  InLoadOrderLinks);
484 
485  TRACE("PeLdrCheckForLoadedDll: DTE %p, EP %p, base %p name '%.*ws'\n",
486  DataTableEntry, DataTableEntry->EntryPoint, DataTableEntry->DllBase,
487  DataTableEntry->BaseDllName.Length / 2, VaToPa(DataTableEntry->BaseDllName.Buffer));
488 
489  /* Compare names */
490  if (PeLdrpCompareDllName(DllName, &DataTableEntry->BaseDllName))
491  {
492  /* Yes, found it, report pointer to the loaded module's DTE
493  to the caller and increase load count for it */
494  *LoadedEntry = DataTableEntry;
495  DataTableEntry->LoadCount++;
496  TRACE("PeLdrCheckForLoadedDll: LoadedEntry %X\n", DataTableEntry);
497  return TRUE;
498  }
499 
500  /* Go to the next entry */
501  ModuleEntry = ModuleEntry->Flink;
502  }
503 
504  /* Nothing found */
505  return FALSE;
506 }
507 
508 BOOLEAN
511  IN PCCH DirectoryPath,
512  IN PLDR_DATA_TABLE_ENTRY ScanDTE)
513 {
514  PLDR_DATA_TABLE_ENTRY DataTableEntry;
515  PIMAGE_IMPORT_DESCRIPTOR ImportTable;
516  ULONG ImportTableSize;
517  PCH ImportName;
519 
520  /* Get a pointer to the import table of this image */
521  ImportTable = (PIMAGE_IMPORT_DESCRIPTOR)RtlImageDirectoryEntryToData(VaToPa(ScanDTE->DllBase),
522  TRUE, IMAGE_DIRECTORY_ENTRY_IMPORT, &ImportTableSize);
523 
524 #if DBG
525  {
526  UNICODE_STRING BaseName;
527  BaseName.Buffer = VaToPa(ScanDTE->BaseDllName.Buffer);
528  BaseName.MaximumLength = ScanDTE->BaseDllName.MaximumLength;
529  BaseName.Length = ScanDTE->BaseDllName.Length;
530  TRACE("PeLdrScanImportDescriptorTable(): %wZ ImportTable = 0x%X\n",
531  &BaseName, ImportTable);
532  }
533 #endif
534 
535  /* If image doesn't have any import directory - just return success */
536  if (ImportTable == NULL)
537  return TRUE;
538 
539  /* Loop through all entries */
540  for (;(ImportTable->Name != 0) && (ImportTable->FirstThunk != 0);ImportTable++)
541  {
542  /* Get pointer to the name */
543  ImportName = (PCH)VaToPa(RVA(ScanDTE->DllBase, ImportTable->Name));
544  TRACE("PeLdrScanImportDescriptorTable(): Looking at %s\n", ImportName);
545 
546  /* In case we get a reference to ourselves - just skip it */
547  if (PeLdrpCompareDllName(ImportName, &ScanDTE->BaseDllName))
548  continue;
549 
550  /* Load the DLL if it is not already loaded */
551  if (!PeLdrCheckForLoadedDll(ModuleListHead, ImportName, &DataTableEntry))
552  {
554  DirectoryPath,
555  ImportName,
556  &ScanDTE->InLoadOrderLinks,
557  &DataTableEntry);
558  if (!Success)
559  {
560  ERR("PeLdrpLoadAndScanReferencedDll() failed\n");
561  return Success;
562  }
563  }
564 
565  /* Scan its import address table */
567  DataTableEntry->DllBase,
568  ScanDTE->DllBase,
569  (PIMAGE_THUNK_DATA)RVA(ScanDTE->DllBase, ImportTable->FirstThunk),
570  DirectoryPath,
571  &ScanDTE->InLoadOrderLinks);
572 
573  if (!Success)
574  {
575  ERR("PeLdrpScanImportAddressTable() failed: ImportName = '%s', DirectoryPath = '%s'\n",
576  ImportName, DirectoryPath);
577  return Success;
578  }
579  }
580 
581  return TRUE;
582 }
583 
584 BOOLEAN
587  IN PCCH BaseDllName,
589  IN PVOID BasePA,
590  OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
591 {
592  PVOID BaseVA = PaToVa(BasePA);
593  PWSTR Buffer;
594  PLDR_DATA_TABLE_ENTRY DataTableEntry;
595  PIMAGE_NT_HEADERS NtHeaders;
596  USHORT Length;
597 
598  TRACE("PeLdrAllocateDataTableEntry(, '%s', '%s', %p)\n",
599  BaseDllName, FullDllName, BasePA);
600 
601  /* Allocate memory for a data table entry, zero-initialize it */
603  TAG_WLDR_DTE);
604  if (DataTableEntry == NULL)
605  return FALSE;
606  RtlZeroMemory(DataTableEntry, sizeof(LDR_DATA_TABLE_ENTRY));
607 
608  /* Get NT headers from the image */
609  NtHeaders = RtlImageNtHeader(BasePA);
610 
611  /* Initialize corresponding fields of DTE based on NT headers value */
612  DataTableEntry->DllBase = BaseVA;
613  DataTableEntry->SizeOfImage = NtHeaders->OptionalHeader.SizeOfImage;
614  DataTableEntry->EntryPoint = RVA(BaseVA, NtHeaders->OptionalHeader.AddressOfEntryPoint);
615  DataTableEntry->SectionPointer = 0;
616  DataTableEntry->CheckSum = NtHeaders->OptionalHeader.CheckSum;
617 
618  /* Initialize BaseDllName field (UNICODE_STRING) from the Ansi BaseDllName
619  by simple conversion - copying each character */
620  Length = (USHORT)(strlen(BaseDllName) * sizeof(WCHAR));
622  if (Buffer == NULL)
623  {
624  FrLdrHeapFree(DataTableEntry, TAG_WLDR_DTE);
625  return FALSE;
626  }
628 
629  DataTableEntry->BaseDllName.Length = Length;
630  DataTableEntry->BaseDllName.MaximumLength = Length;
631  DataTableEntry->BaseDllName.Buffer = PaToVa(Buffer);
632  while (*BaseDllName != 0)
633  {
634  *Buffer++ = *BaseDllName++;
635  }
636 
637  /* Initialize FullDllName field (UNICODE_STRING) from the Ansi FullDllName
638  using the same method */
639  Length = (USHORT)(strlen(FullDllName) * sizeof(WCHAR));
641  if (Buffer == NULL)
642  {
643  FrLdrHeapFree(DataTableEntry, TAG_WLDR_DTE);
644  return FALSE;
645  }
647 
648  DataTableEntry->FullDllName.Length = Length;
649  DataTableEntry->FullDllName.MaximumLength = Length;
650  DataTableEntry->FullDllName.Buffer = PaToVa(Buffer);
651  while (*FullDllName != 0)
652  {
653  *Buffer++ = *FullDllName++;
654  }
655 
656  /* Initialize what's left - LoadCount which is 1, and set Flags so that
657  we know this entry is processed */
658  DataTableEntry->Flags = LDRP_ENTRY_PROCESSED;
659  DataTableEntry->LoadCount = 1;
660 
661  /* Honour the FORCE_INTEGRITY flag */
663  {
664  /*
665  * On Vista and above, the LDRP_IMAGE_INTEGRITY_FORCED flag must be set
666  * if IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY is set in the image header.
667  * This is done after the image has been loaded and the digital signature
668  * check has passed successfully. (We do not do it yet!)
669  *
670  * Several OS functionality depend on the presence of this flag.
671  * For example, when using Object-Manager callbacks the latter will call
672  * MmVerifyCallbackFunction() to verify whether the flag is present.
673  * If not callbacks will not work.
674  * (See Windows Internals Part 1, 6th edition, p. 176.)
675  */
676  DataTableEntry->Flags |= LDRP_IMAGE_INTEGRITY_FORCED;
677  }
678 
679  /* Insert this DTE to a list in the LPB */
681  TRACE("Inserting DTE %p, name='%.*S' DllBase=%p \n", DataTableEntry,
682  DataTableEntry->BaseDllName.Length / 2,
683  VaToPa(DataTableEntry->BaseDllName.Buffer),
684  DataTableEntry->DllBase);
685 
686  /* Save pointer to a newly allocated and initialized entry */
687  *NewEntry = DataTableEntry;
688 
689  /* Return success */
690  return TRUE;
691 }
692 
693 /*
694  * PeLdrLoadImage loads the specified image from the file (it doesn't
695  * perform any additional operations on the filename, just directly
696  * calls the file I/O routines), and relocates it so that it's ready
697  * to be used when paging is enabled.
698  * Addressing mode: physical
699  */
700 BOOLEAN
702  IN PCHAR FileName,
703  IN TYPE_OF_MEMORY MemoryType,
704  OUT PVOID *ImageBasePA)
705 {
706  ULONG FileId;
707  PVOID PhysicalBase;
708  PVOID VirtualBase = NULL;
709  UCHAR HeadersBuffer[SECTOR_SIZE * 2];
710  PIMAGE_NT_HEADERS NtHeaders;
711  PIMAGE_SECTION_HEADER SectionHeader;
712  ULONG VirtualSize, SizeOfRawData, NumberOfSections;
715  ULONG i, BytesRead;
716 
717  TRACE("PeLdrLoadImage(%s, %ld, *)\n", FileName, MemoryType);
718 
719  /* Open the image file */
720  Status = ArcOpen((PSTR)FileName, OpenReadOnly, &FileId);
721  if (Status != ESUCCESS)
722  {
723  WARN("ArcOpen(FileName: '%s') failed. Status: %u\n", FileName, Status);
724  return FALSE;
725  }
726 
727  /* Load the first 2 sectors of the image so we can read the PE header */
728  Status = ArcRead(FileId, HeadersBuffer, SECTOR_SIZE * 2, &BytesRead);
729  if (Status != ESUCCESS)
730  {
731  ERR("ArcRead(File: '%s') failed. Status: %u\n", FileName, Status);
732  UiMessageBox("Error reading from file.");
733  ArcClose(FileId);
734  return FALSE;
735  }
736 
737  /* Now read the MZ header to get the offset to the PE Header */
738  NtHeaders = RtlImageNtHeader(HeadersBuffer);
739  if (!NtHeaders)
740  {
741  ERR("No NT header found in \"%s\"\n", FileName);
742  UiMessageBox("Error: No NT header found.");
743  ArcClose(FileId);
744  return FALSE;
745  }
746 
747  /* Ensure this is executable image */
748  if (((NtHeaders->FileHeader.Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0))
749  {
750  ERR("Not an executable image \"%s\"\n", FileName);
751  UiMessageBox("Not an executable image.");
752  ArcClose(FileId);
753  return FALSE;
754  }
755 
756  /* Store number of sections to read and a pointer to the first section */
757  NumberOfSections = NtHeaders->FileHeader.NumberOfSections;
758  SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
759 
760  /* Try to allocate this memory, if fails - allocate somewhere else */
761  PhysicalBase = MmAllocateMemoryAtAddress(NtHeaders->OptionalHeader.SizeOfImage,
762  (PVOID)((ULONG)NtHeaders->OptionalHeader.ImageBase & (KSEG0_BASE - 1)),
763  MemoryType);
764 
765  if (PhysicalBase == NULL)
766  {
767  /* It's ok, we don't panic - let's allocate again at any other "low" place */
768  PhysicalBase = MmAllocateMemoryWithType(NtHeaders->OptionalHeader.SizeOfImage, MemoryType);
769 
770  if (PhysicalBase == NULL)
771  {
772  ERR("Failed to alloc %lu bytes for image %s\n", NtHeaders->OptionalHeader.SizeOfImage, FileName);
773  UiMessageBox("Failed to alloc pages for image.");
774  ArcClose(FileId);
775  return FALSE;
776  }
777  }
778 
779  /* This is the real image base - in form of a virtual address */
780  VirtualBase = PaToVa(PhysicalBase);
781 
782  TRACE("Base PA: 0x%X, VA: 0x%X\n", PhysicalBase, VirtualBase);
783 
784  /* Set to 0 position and fully load the file image */
785  Position.QuadPart = 0;
786  Status = ArcSeek(FileId, &Position, SeekAbsolute);
787  if (Status != ESUCCESS)
788  {
789  ERR("ArcSeek(File: '%s') failed. Status: 0x%lx\n", FileName, Status);
790  UiMessageBox("Error seeking the start of a file.");
791  ArcClose(FileId);
792  return FALSE;
793  }
794 
795  Status = ArcRead(FileId, PhysicalBase, NtHeaders->OptionalHeader.SizeOfHeaders, &BytesRead);
796  if (Status != ESUCCESS)
797  {
798  ERR("ArcRead(File: '%s') failed. Status: %u\n", FileName, Status);
799  UiMessageBox("Error reading headers.");
800  ArcClose(FileId);
801  return FALSE;
802  }
803 
804  /*
805  * On Vista and above, a digital signature check is performed when the image
806  * has the IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY flag set in its header.
807  * (We of course do not perform this check yet!)
808  */
809 
810  /* Reload the NT Header */
811  NtHeaders = RtlImageNtHeader(PhysicalBase);
812 
813  /* Load the first section */
814  SectionHeader = IMAGE_FIRST_SECTION(NtHeaders);
815 
816  /* Fill output parameters */
817  *ImageBasePA = PhysicalBase;
818 
819  /* Walk through each section and read it (check/fix any possible
820  bad situations, if they arise) */
821  for (i = 0; i < NumberOfSections; i++)
822  {
823  VirtualSize = SectionHeader->Misc.VirtualSize;
824  SizeOfRawData = SectionHeader->SizeOfRawData;
825 
826  /* Handle a case when VirtualSize equals 0 */
827  if (VirtualSize == 0)
828  VirtualSize = SizeOfRawData;
829 
830  /* If PointerToRawData is 0, then force its size to be also 0 */
831  if (SectionHeader->PointerToRawData == 0)
832  {
833  SizeOfRawData = 0;
834  }
835  else
836  {
837  /* Cut the loaded size to the VirtualSize extents */
838  if (SizeOfRawData > VirtualSize)
839  SizeOfRawData = VirtualSize;
840  }
841 
842  /* Actually read the section (if its size is not 0) */
843  if (SizeOfRawData != 0)
844  {
845  /* Seek to the correct position */
846  Position.LowPart = SectionHeader->PointerToRawData;
847  Status = ArcSeek(FileId, &Position, SeekAbsolute);
848 
849  TRACE("SH->VA: 0x%X\n", SectionHeader->VirtualAddress);
850 
851  /* Read this section from the file, size = SizeOfRawData */
852  Status = ArcRead(FileId, (PUCHAR)PhysicalBase + SectionHeader->VirtualAddress, SizeOfRawData, &BytesRead);
853  if (Status != ESUCCESS)
854  {
855  ERR("PeLdrLoadImage(): Error reading section from file!\n");
856  break;
857  }
858  }
859 
860  /* Size of data is less than the virtual size - fill up the remainder with zeroes */
861  if (SizeOfRawData < VirtualSize)
862  {
863  TRACE("PeLdrLoadImage(): SORD %d < VS %d\n", SizeOfRawData, VirtualSize);
864  RtlZeroMemory((PVOID)(SectionHeader->VirtualAddress + (ULONG_PTR)PhysicalBase + SizeOfRawData), VirtualSize - SizeOfRawData);
865  }
866 
867  SectionHeader++;
868  }
869 
870  /* We are done with the file - close it */
871  ArcClose(FileId);
872 
873  /* If loading failed - return right now */
874  if (Status != ESUCCESS)
875  return FALSE;
876 
877  /* Relocate the image, if it needs it */
878  if (NtHeaders->OptionalHeader.ImageBase != (ULONG_PTR)VirtualBase)
879  {
880  WARN("Relocating %p -> %p\n", NtHeaders->OptionalHeader.ImageBase, VirtualBase);
881  return (BOOLEAN)LdrRelocateImageWithBias(PhysicalBase,
882  (ULONG_PTR)VirtualBase - (ULONG_PTR)PhysicalBase,
883  "FreeLdr",
884  TRUE,
885  TRUE, /* in case of conflict still return success */
886  FALSE);
887  }
888 
889  TRACE("PeLdrLoadImage() done, PA = %p\n", *ImageBasePA);
890  return TRUE;
891 }
signed char * PCHAR
Definition: retypes.h:7
#define TAG_WLDR_DTE
Definition: winldr.h:13
#define LDRP_ENTRY_PROCESSED
Definition: ldrtypes.h:44
#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
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
uint16_t * PWSTR
Definition: typedefs.h:54
static BOOLEAN PeLdrpBindImportName(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, IN PLIST_ENTRY Parent)
Definition: peloader.c:89
BOOLEAN PeLdrScanImportDescriptorTable(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH DirectoryPath, IN PLDR_DATA_TABLE_ENTRY ScanDTE)
Definition: peloader.c:509
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:143
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
BOOLEAN PeLdrCheckForLoadedDll(IN OUT PLIST_ENTRY ModuleListHead, IN PCH DllName, OUT PLDR_DATA_TABLE_ENTRY *LoadedEntry)
Definition: peloader.c:465
#define IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
Definition: ntimage.h:456
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn BOOLEAN Physical UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE Parent
Definition: acpixf.h:722
_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
#define LDRP_DRIVER_DEPENDENT_DLL
Definition: ldrtypes.h:56
IMAGE_OPTIONAL_HEADER32 OptionalHeader
Definition: ntddk_ex.h:184
enum _TYPE_OF_MEMORY TYPE_OF_MEMORY
uint32_t ULONG_PTR
Definition: typedefs.h:63
BOOLEAN PeLdrLoadImage(IN PCHAR FileName, IN TYPE_OF_MEMORY MemoryType, OUT PVOID *ImageBasePA)
Definition: peloader.c:701
PVOID DllBase
Definition: btrfs_drv.h:1784
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 LDRP_IMAGE_INTEGRITY_FORCED
Definition: ldrtypes.h:41
#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
VOID UiMessageBox(PCSTR Format,...)
Definition: ui.c:320
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:247
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
#define TAG_WLDR_NAME
Definition: winldr.h:15
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:1790
#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:236
unsigned char UCHAR
Definition: xmlstorage.h:181
union _IMAGE_THUNK_DATA32::@2055 u1
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:243
Definition: btrfs_drv.h:1780
Definition: typedefs.h:117
PVOID MmAllocateMemoryAtAddress(SIZE_T MemorySize, PVOID DesiredAddress, TYPE_OF_MEMORY MemoryType)
Definition: mm.c:85
BOOLEAN PeLdrAllocateDataTableEntry(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH BaseDllName, IN PCCH FullDllName, IN PVOID BasePA, OUT PLDR_DATA_TABLE_ENTRY *NewEntry)
Definition: peloader.c:585
#define IMAGE_DIRECTORY_ENTRY_EXPORT
Definition: compat.h:140
static BOOLEAN PeLdrpCompareDllName(IN PCH DllName, IN PUNICODE_STRING UnicodeName)
Definition: peloader.c:30
Status
Definition: gdiplustypes.h:24
LIST_ENTRY InLoadOrderLinks
Definition: ldrtypes.h:138
#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
signed char * PSTR
Definition: retypes.h:7
UNICODE_STRING FullDllName
Definition: btrfs_drv.h:1786
UNICODE_STRING BaseDllName
Definition: ldrtypes.h:145
unsigned int * PULONG
Definition: retypes.h:1
struct _IMAGE_EXPORT_DIRECTORY * PIMAGE_EXPORT_DIRECTORY
static BOOLEAN PeLdrpScanImportAddressTable(IN OUT PLIST_ENTRY ModuleListHead, IN PVOID DllBase, IN PVOID ImageBase, IN PIMAGE_THUNK_DATA ThunkData, IN PCSTR DirectoryPath, IN PLIST_ENTRY Parent)
Definition: peloader.c:395
char * strchr(const char *String, int ch)
Definition: utclib.c:501
ARC_STATUS ArcClose(ULONG FileId)
Definition: fs.c:218
#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:56
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
#define SECTOR_SIZE
Definition: fs.h:22
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
union _IMAGE_SECTION_HEADER::@1528 Misc
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
USHORT LoadCount
Definition: ntddk_ex.h:208
static BOOLEAN PeLdrpLoadAndScanReferencedDll(IN OUT PLIST_ENTRY ModuleListHead, IN PCCH DirectoryPath, IN PCH ImportName, IN PLIST_ENTRY Parent OPTIONAL, OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry)
Definition: peloader.c:342
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68