xref: /reactos/dll/ntdll/ldr/ldrpe.c (revision 9393fc32)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            lib/ntdll/ldr/ldrpe.c
5  * PURPOSE:         Loader Functions dealing low-level PE Format structures
6  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include <ntdll.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* GLOBALS *******************************************************************/
17 
18 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine;
19 ULONG LdrpNormalSnap;
20 
21 /* FUNCTIONS *****************************************************************/
22 
23 
24 NTSTATUS
25 NTAPI
26 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,
27             IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,
28             IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,
29             IN BOOLEAN EntriesValid)
30 {
31     PVOID Iat;
32     NTSTATUS Status;
33     PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
34     PIMAGE_NT_HEADERS NtHeader;
35     PIMAGE_SECTION_HEADER SectionHeader;
36     PIMAGE_EXPORT_DIRECTORY ExportDirectory;
37     LPSTR ImportName;
38     ULONG ForwarderChain, i, Rva, OldProtect, IatSize, ExportSize;
39     SIZE_T ImportSize;
40     DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid);
41 
42     /* Get export directory */
43     ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase,
44                                                    TRUE,
45                                                    IMAGE_DIRECTORY_ENTRY_EXPORT,
46                                                    &ExportSize);
47 
48     /* Make sure it has one */
49     if (!ExportDirectory)
50     {
51         /* Fail */
52         DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
53                  &ExportLdrEntry->BaseDllName);
54         return STATUS_INVALID_IMAGE_FORMAT;
55     }
56 
57     /* Get the IAT */
58     Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase,
59                                        TRUE,
60                                        IMAGE_DIRECTORY_ENTRY_IAT,
61                                        &IatSize);
62     ImportSize = IatSize;
63 
64     /* Check if we don't have one */
65     if (!Iat)
66     {
67         /* Get the NT Header and the first section */
68         NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
69         if (!NtHeader) return STATUS_INVALID_IMAGE_FORMAT;
70         SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
71 
72         /* Get the RVA of the import directory */
73         Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
74 
75         /* Make sure we got one */
76         if (Rva)
77         {
78             /* Loop all the sections */
79             for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
80             {
81                 /* Check if we are inside this section */
82                 if ((Rva >= SectionHeader->VirtualAddress) &&
83                     (Rva < (SectionHeader->VirtualAddress +
84                      SectionHeader->SizeOfRawData)))
85                 {
86                     /* We are, so set the IAT here */
87                     Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) +
88                                       SectionHeader->VirtualAddress);
89 
90                     /* Set the size */
91                     IatSize = SectionHeader->Misc.VirtualSize;
92 
93                     /* Deal with Watcom and other retarded compilers */
94                     if (!IatSize) IatSize = SectionHeader->SizeOfRawData;
95 
96                     /* Found it, get out */
97                     break;
98                 }
99 
100                 /* No match, move to the next section */
101                 SectionHeader++;
102             }
103         }
104 
105         /* If we still don't have an IAT, that's bad */
106         if (!Iat)
107         {
108             /* Fail */
109             DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
110                      &ImportLdrEntry->BaseDllName,
111                      ImportLdrEntry->DllBase);
112             return STATUS_INVALID_IMAGE_FORMAT;
113         }
114 
115         /* Set the right size */
116         ImportSize = IatSize;
117     }
118 
119     /* Unprotect the IAT */
120     Status = NtProtectVirtualMemory(NtCurrentProcess(),
121                                     &Iat,
122                                     &ImportSize,
123                                     PAGE_READWRITE,
124                                     &OldProtect);
125     if (!NT_SUCCESS(Status))
126     {
127         /* Fail */
128         DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
129                  &ImportLdrEntry->BaseDllName,
130                  Status);
131         return Status;
132     }
133 
134     /* Check if the Thunks are already valid */
135     if (EntriesValid)
136     {
137         /* We'll only do forwarders. Get the import name */
138         ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name);
139 
140         /* Get the list of forwarders */
141         ForwarderChain = IatEntry->ForwarderChain;
142 
143         /* Loop them */
144         while (ForwarderChain != -1)
145         {
146             /* Get the cached thunk VA*/
147             OriginalThunk = (PIMAGE_THUNK_DATA)
148                             ((ULONG_PTR)ImportLdrEntry->DllBase +
149                              IatEntry->OriginalFirstThunk +
150                              (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
151 
152             /* Get the first thunk */
153             FirstThunk = (PIMAGE_THUNK_DATA)
154                          ((ULONG_PTR)ImportLdrEntry->DllBase +
155                           IatEntry->FirstThunk +
156                           (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
157 
158             /* Get the Forwarder from the thunk */
159             ForwarderChain = (ULONG)FirstThunk->u1.Ordinal;
160 
161             /* Snap the thunk */
162             _SEH2_TRY
163             {
164                 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
165                                        ImportLdrEntry->DllBase,
166                                        OriginalThunk,
167                                        FirstThunk,
168                                        ExportDirectory,
169                                        ExportSize,
170                                        TRUE,
171                                        ImportName);
172 
173                 /* Move to the next thunk */
174                 FirstThunk++;
175             } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
176             {
177                 /* Fail with the SEH error */
178                 Status = _SEH2_GetExceptionCode();
179             } _SEH2_END;
180 
181             /* If we messed up, exit */
182             if (!NT_SUCCESS(Status)) break;
183         }
184     }
185     else if (IatEntry->FirstThunk)
186     {
187         /* Full snapping. Get the First thunk */
188         FirstThunk = (PIMAGE_THUNK_DATA)
189                       ((ULONG_PTR)ImportLdrEntry->DllBase +
190                        IatEntry->FirstThunk);
191 
192         /* Get the NT Header */
193         NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
194 
195         /* Get the Original thunk VA, watch out for weird images */
196         if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) ||
197             (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage))
198         {
199             /* Refuse it, this is a strange linked file */
200             OriginalThunk = FirstThunk;
201         }
202         else
203         {
204             /* Get the address from the field and convert to VA */
205             OriginalThunk = (PIMAGE_THUNK_DATA)
206                             ((ULONG_PTR)ImportLdrEntry->DllBase +
207                              IatEntry->OriginalFirstThunk);
208         }
209 
210         /* Get the Import name VA */
211         ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase +
212                              IatEntry->Name);
213 
214         /* Loop while it's valid */
215         while (OriginalThunk->u1.AddressOfData)
216         {
217             /* Snap the Thunk */
218             _SEH2_TRY
219             {
220                 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
221                                        ImportLdrEntry->DllBase,
222                                        OriginalThunk,
223                                        FirstThunk,
224                                        ExportDirectory,
225                                        ExportSize,
226                                        TRUE,
227                                        ImportName);
228 
229                 /* Next thunks */
230                 OriginalThunk++;
231                 FirstThunk++;
232             } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
233             {
234                 /* Fail with the SEH error */
235                 Status = _SEH2_GetExceptionCode();
236             } _SEH2_END;
237 
238             /* If we failed the snap, break out */
239             if (!NT_SUCCESS(Status)) break;
240         }
241     }
242 
243     /* Protect the IAT again */
244     NtProtectVirtualMemory(NtCurrentProcess(),
245                            &Iat,
246                            &ImportSize,
247                            OldProtect,
248                            &OldProtect);
249 
250     /* Also flush out the cache */
251     NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize);
252 
253     /* Return to Caller */
254     return Status;
255 }
256 
257 NTSTATUS
258 NTAPI
259 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
260                                        IN PLDR_DATA_TABLE_ENTRY LdrEntry,
261                                        IN PIMAGE_BOUND_IMPORT_DESCRIPTOR *BoundEntryPtr,
262                                        IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry)
263 {
264     LPSTR ImportName = NULL, BoundImportName, ForwarderName;
265     NTSTATUS Status;
266     BOOLEAN AlreadyLoaded = FALSE, Stale;
267     PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
268     PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry;
269     PIMAGE_BOUND_FORWARDER_REF ForwarderEntry;
270     PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry;
271     PPEB Peb = NtCurrentPeb();
272     ULONG i, IatSize;
273 
274     /* Get the pointer to the bound entry */
275     BoundEntry = *BoundEntryPtr;
276 
277     /* Get the name's VA */
278     BoundImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName;
279 
280     /* Show debug message */
281     if (ShowSnaps)
282     {
283         DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName);
284     }
285 
286     /* Load the module for this entry */
287     Status = LdrpLoadImportModule(DllPath,
288                                   BoundImportName,
289                                   &DllLdrEntry,
290                                   &AlreadyLoaded);
291     if (!NT_SUCCESS(Status))
292     {
293         /* Show debug message */
294         if (ShowSnaps)
295         {
296             DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
297                     &LdrEntry->BaseDllName,
298                     BoundImportName,
299                     Status);
300         }
301         goto Quickie;
302     }
303 
304     /* Check if it wasn't already loaded */
305     if (!AlreadyLoaded)
306     {
307         /* Add it to our list */
308         InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
309                        &DllLdrEntry->InInitializationOrderLinks);
310     }
311 
312     /* Check if the Bound Entry is now invalid */
313     if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) ||
314         (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
315     {
316         /* Show debug message */
317         if (ShowSnaps)
318         {
319             DPRINT1("LDR: %wZ has stale binding to %s\n",
320                     &LdrEntry->BaseDllName,
321                     BoundImportName);
322         }
323 
324         /* Remember it's become stale */
325         Stale = TRUE;
326     }
327     else
328     {
329         /* Show debug message */
330         if (ShowSnaps)
331         {
332             DPRINT1("LDR: %wZ has correct binding to %s\n",
333                     &LdrEntry->BaseDllName,
334                     BoundImportName);
335         }
336 
337         /* Remember it's valid */
338         Stale = FALSE;
339     }
340 
341     /* Get the forwarders */
342     ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1);
343 
344     /* Loop them */
345     for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++)
346     {
347         /* Get the name */
348         ForwarderName = (LPSTR)FirstEntry + ForwarderEntry->OffsetModuleName;
349 
350         /* Show debug message */
351         if (ShowSnaps)
352         {
353             DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
354                     &LdrEntry->BaseDllName,
355                     ForwarderName,
356                     &DllLdrEntry->BaseDllName);
357         }
358 
359         /* Load the module */
360         Status = LdrpLoadImportModule(DllPath,
361                                       ForwarderName,
362                                       &ForwarderLdrEntry,
363                                       &AlreadyLoaded);
364         if (NT_SUCCESS(Status))
365         {
366             /* Loaded it, was it already loaded? */
367             if (!AlreadyLoaded)
368             {
369                 /* Add it to our list */
370                 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
371                                &ForwarderLdrEntry->InInitializationOrderLinks);
372             }
373         }
374 
375         /* Check if the Bound Entry is now invalid */
376         if (!(NT_SUCCESS(Status)) ||
377             (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) ||
378             (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
379         {
380             /* Show debug message */
381             if (ShowSnaps)
382             {
383                 DPRINT1("LDR: %wZ has stale binding to %s\n",
384                         &LdrEntry->BaseDllName,
385                         ForwarderName);
386             }
387 
388             /* Remember it's become stale */
389             Stale = TRUE;
390         }
391         else
392         {
393             /* Show debug message */
394             if (ShowSnaps)
395             {
396                 DPRINT1("LDR: %wZ has correct binding to %s\n",
397                         &LdrEntry->BaseDllName,
398                         ForwarderName);
399             }
400 
401             /* Remember it's valid */
402             Stale = FALSE;
403         }
404 
405         /* Move to the next one */
406         ForwarderEntry++;
407     }
408 
409     /* Set the next bound entry to the forwarder */
410     FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry;
411 
412     /* Check if the binding was stale */
413     if (Stale)
414     {
415         /* It was, so find the IAT entry for it */
416         ++LdrpNormalSnap;
417         ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
418                                                    TRUE,
419                                                    IMAGE_DIRECTORY_ENTRY_IMPORT,
420                                                    &IatSize);
421 
422         /* Make sure it has a name */
423         while (ImportEntry->Name)
424         {
425             /* Get the name */
426             ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
427 
428             /* Compare it */
429             if (!_stricmp(ImportName, BoundImportName)) break;
430 
431             /* Move to next entry */
432             ImportEntry++;
433         }
434 
435         /* If we didn't find a name, fail */
436         if (!ImportEntry->Name)
437         {
438             /* Show debug message */
439             if (ShowSnaps)
440             {
441                 DPRINT1("LDR: LdrpWalkImportTable - failing with"
442                         "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
443             }
444 
445             /* Return error */
446             Status = STATUS_OBJECT_NAME_INVALID;
447             goto Quickie;
448         }
449 
450         /* Show debug message */
451         if (ShowSnaps)
452         {
453             DPRINT1("LDR: Stale Bind %s from %wZ\n",
454                     ImportName,
455                     &LdrEntry->BaseDllName);
456         }
457 
458         /* Snap the IAT Entry*/
459         Status = LdrpSnapIAT(DllLdrEntry,
460                              LdrEntry,
461                              ImportEntry,
462                              FALSE);
463 
464         /* Make sure we didn't fail */
465         if (!NT_SUCCESS(Status))
466         {
467             /* Show debug message */
468             if (ShowSnaps)
469             {
470                 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
471                         &LdrEntry->BaseDllName,
472                         BoundImportName,
473                         Status);
474             }
475 
476             /* Return */
477             goto Quickie;
478         }
479     }
480 
481     /* All done */
482     Status = STATUS_SUCCESS;
483 
484 Quickie:
485     /* Write where we are now and return */
486     *BoundEntryPtr = FirstEntry;
487     return Status;
488 }
489 
490 NTSTATUS
491 NTAPI
492 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
493                                     IN PLDR_DATA_TABLE_ENTRY LdrEntry,
494                                     IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)
495 {
496     PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry;
497     NTSTATUS Status;
498 
499     /* Make sure we have a name */
500     while (BoundEntry->OffsetModuleName)
501     {
502         /* Parse this descriptor */
503         Status = LdrpHandleOneNewFormatImportDescriptor(DllPath,
504                                                         LdrEntry,
505                                                         &BoundEntry,
506                                                         FirstEntry);
507         if (!NT_SUCCESS(Status)) return Status;
508     }
509 
510     /* Done */
511     return STATUS_SUCCESS;
512 }
513 
514 NTSTATUS
515 NTAPI
516 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
517                                        IN PLDR_DATA_TABLE_ENTRY LdrEntry,
518                                        IN PIMAGE_IMPORT_DESCRIPTOR *ImportEntry)
519 {
520     LPSTR ImportName;
521     NTSTATUS Status;
522     BOOLEAN AlreadyLoaded = FALSE;
523     PLDR_DATA_TABLE_ENTRY DllLdrEntry;
524     PIMAGE_THUNK_DATA FirstThunk;
525     PPEB Peb = NtCurrentPeb();
526 
527     /* Get the import name's VA */
528     ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + (*ImportEntry)->Name);
529 
530     /* Get the first thunk */
531     FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase +
532                                      (*ImportEntry)->FirstThunk);
533 
534     /* Make sure it's valid */
535     if (!FirstThunk->u1.Function) goto SkipEntry;
536 
537     /* Show debug message */
538     if (ShowSnaps)
539     {
540         DPRINT1("LDR: %s used by %wZ\n",
541                 ImportName,
542                 &LdrEntry->BaseDllName);
543     }
544 
545     /* Load the module associated to it */
546     Status = LdrpLoadImportModule(DllPath,
547                                   ImportName,
548                                   &DllLdrEntry,
549                                   &AlreadyLoaded);
550     if (!NT_SUCCESS(Status))
551     {
552         /* Fail */
553         if (ShowSnaps)
554         {
555             DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
556                      "on import %s with status %x\n",
557                      ImportName,
558                      Status);
559         }
560 
561         /* Return */
562         return Status;
563     }
564 
565     /* Show debug message */
566     if (ShowSnaps)
567     {
568         DPRINT1("LDR: Snapping imports for %wZ from %s\n",
569                 &LdrEntry->BaseDllName,
570                 ImportName);
571     }
572 
573     /* Check if it wasn't already loaded */
574     ++LdrpNormalSnap;
575     if (!AlreadyLoaded)
576     {
577         /* Add the DLL to our list */
578         InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
579                        &DllLdrEntry->InInitializationOrderLinks);
580     }
581 
582     /* Now snap the IAT Entry */
583     Status = LdrpSnapIAT(DllLdrEntry, LdrEntry, *ImportEntry, FALSE);
584     if (!NT_SUCCESS(Status))
585     {
586         /* Fail */
587         if (ShowSnaps)
588         {
589             DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
590                      "status %x\n",
591                      Status);
592         }
593 
594         /* Return */
595         return Status;
596     }
597 
598 SkipEntry:
599     /* Move on */
600     (*ImportEntry)++;
601     return STATUS_SUCCESS;
602 }
603 
604 NTSTATUS
605 NTAPI
606 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
607                                      IN PLDR_DATA_TABLE_ENTRY LdrEntry,
608                                      IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
609 {
610     NTSTATUS Status;
611 
612     /* Check for Name and Thunk */
613     while ((ImportEntry->Name) && (ImportEntry->FirstThunk))
614     {
615         /* Parse this descriptor */
616         Status = LdrpHandleOneOldFormatImportDescriptor(DllPath,
617                                                         LdrEntry,
618                                                         &ImportEntry);
619         if (!NT_SUCCESS(Status)) return Status;
620     }
621 
622     /* Done */
623     return STATUS_SUCCESS;
624 }
625 
626 USHORT
627 NTAPI
628 LdrpNameToOrdinal(IN LPSTR ImportName,
629                   IN ULONG NumberOfNames,
630                   IN PVOID ExportBase,
631                   IN PULONG NameTable,
632                   IN PUSHORT OrdinalTable)
633 {
634     LONG Start, End, Next, CmpResult;
635 
636     /* Use classical binary search to find the ordinal */
637     Start = Next = 0;
638     End = NumberOfNames - 1;
639     while (End >= Start)
640     {
641         /* Next will be exactly between Start and End */
642         Next = (Start + End) >> 1;
643 
644         /* Compare this name with the one we need to find */
645         CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next]));
646 
647         /* We found our entry if result is 0 */
648         if (!CmpResult) break;
649 
650         /* We didn't find, update our range then */
651         if (CmpResult < 0)
652         {
653             End = Next - 1;
654         }
655         else if (CmpResult > 0)
656         {
657             Start = Next + 1;
658         }
659     }
660 
661     /* If end is before start, then the search failed */
662     if (End < Start) return -1;
663 
664     /* Return found name */
665     return OrdinalTable[Next];
666 }
667 
668 NTSTATUS
669 NTAPI
670 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
671                          IN PLDR_DATA_TABLE_ENTRY LdrEntry)
672 {
673     RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
674     PPEB Peb = NtCurrentPeb();
675     NTSTATUS Status = STATUS_SUCCESS, Status2;
676     PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
677     PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
678     ULONG BoundSize, IatSize;
679 
680     DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry->BaseDllName, LdrEntry, DllPath);
681 
682     /* Set up the Act Ctx */
683     RtlZeroMemory(&ActCtx, sizeof(ActCtx));
684     ActCtx.Size = sizeof(ActCtx);
685     ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
686 
687     /* Check if we have a manifest prober routine */
688     if (LdrpManifestProberRoutine)
689     {
690         /* Probe the DLL for its manifest. Some details are omitted */
691         Status2 = LdrpManifestProberRoutine(LdrEntry->DllBase, LdrEntry->FullDllName.Buffer, &LdrEntry->EntryPointActivationContext);
692 
693         if (!NT_SUCCESS(Status2) &&
694             Status2 != STATUS_NO_SUCH_FILE &&
695             Status2 != STATUS_RESOURCE_DATA_NOT_FOUND &&
696             Status2 != STATUS_RESOURCE_TYPE_NOT_FOUND &&
697             Status2 != STATUS_RESOURCE_NAME_NOT_FOUND &&
698             Status2 != STATUS_RESOURCE_LANG_NOT_FOUND)
699         {
700             /* Some serious issue */
701             //Status = Status2; // FIXME: Ignore that error for now
702             DbgPrintEx(DPFLTR_SXS_ID,
703                 DPFLTR_WARNING_LEVEL,
704                 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
705                 "manifest, ntstatus = 0x%08lx\n",
706                 &LdrEntry->FullDllName, Status2);
707         }
708     }
709 
710     /* Check if we failed above */
711     if (!NT_SUCCESS(Status)) return Status;
712 
713     /* Get the Active ActCtx */
714     if (!LdrEntry->EntryPointActivationContext)
715     {
716         Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
717 
718         if (!NT_SUCCESS(Status))
719         {
720             /* Exit */
721             DbgPrintEx(DPFLTR_SXS_ID,
722                 DPFLTR_WARNING_LEVEL,
723                 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
724                 "0x%08lx\n",
725                 Status);
726             return Status;
727         }
728     }
729 
730     /* Activate the ActCtx */
731     RtlActivateActivationContextUnsafeFast(&ActCtx,
732                                            LdrEntry->EntryPointActivationContext);
733 
734     /* Check if we were redirected */
735     if (!(LdrEntry->Flags & LDRP_REDIRECTED))
736     {
737         /* Get the Bound IAT */
738         BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
739                                                   TRUE,
740                                                   IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
741                                                   &BoundSize);
742     }
743 
744     /* Get the regular IAT, for fallback */
745     ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
746                                                TRUE,
747                                                IMAGE_DIRECTORY_ENTRY_IMPORT,
748                                                &IatSize);
749 
750     /* Check if we got at least one */
751     if ((BoundEntry) || (ImportEntry))
752     {
753         /* Do we have a Bound IAT */
754         if (BoundEntry)
755         {
756             /* Handle the descriptor */
757             Status = LdrpHandleNewFormatImportDescriptors(DllPath,
758                                                           LdrEntry,
759                                                           BoundEntry);
760         }
761         else
762         {
763             /* Handle the descriptor */
764             Status = LdrpHandleOldFormatImportDescriptors(DllPath,
765                                                           LdrEntry,
766                                                           ImportEntry);
767         }
768 
769         /* Check the status of the handlers */
770         if (NT_SUCCESS(Status))
771         {
772             /* Check for Per-DLL Heap Tagging */
773             if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
774             {
775                 /* FIXME */
776                 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
777             }
778 
779             /* Check if Page Heap was enabled */
780             if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
781             {
782                 /* Initialize target DLL */
783                 AVrfPageHeapDllNotification(LdrEntry);
784             }
785 
786             /* Check if Application Verifier was enabled */
787             if (Peb->NtGlobalFlag & FLG_APPLICATION_VERIFIER)
788             {
789                 AVrfDllLoadNotification(LdrEntry);
790             }
791 
792             /* Just to be safe */
793             Status = STATUS_SUCCESS;
794         }
795     }
796 
797     /* Release the activation context */
798     RtlDeactivateActivationContextUnsafeFast(&ActCtx);
799 
800     DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry->BaseDllName, LdrEntry);
801 
802     /* Return status */
803     return Status;
804 }
805 
806 NTSTATUS
807 NTAPI
808 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
809                      IN LPSTR ImportName,
810                      OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
811                      OUT PBOOLEAN Existing)
812 {
813     ANSI_STRING AnsiString;
814     PUNICODE_STRING ImpDescName;
815     const WCHAR *p;
816     BOOLEAN GotExtension;
817     WCHAR c;
818     NTSTATUS Status;
819     PPEB Peb = RtlGetCurrentPeb();
820     PTEB Teb = NtCurrentTeb();
821     UNICODE_STRING RedirectedImpDescName;
822     BOOLEAN RedirectedDll;
823 
824     DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath, ImportName, DataTableEntry, Existing);
825 
826     RedirectedDll = FALSE;
827     RtlInitEmptyUnicodeString(&RedirectedImpDescName, NULL, 0);
828 
829     /* Convert import descriptor name to unicode string */
830     ImpDescName = &Teb->StaticUnicodeString;
831     RtlInitAnsiString(&AnsiString, ImportName);
832     Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE);
833     if (!NT_SUCCESS(Status)) return Status;
834 
835     /* Find the extension, if present */
836     p = ImpDescName->Buffer + ImpDescName->Length / sizeof(WCHAR) - 1;
837     GotExtension = FALSE;
838     while (p >= ImpDescName->Buffer)
839     {
840         c = *p--;
841         if (c == L'.')
842         {
843             GotExtension = TRUE;
844             break;
845         }
846         else if (c == L'\\')
847         {
848             break;
849         }
850     }
851 
852     /* If no extension was found, add the default extension */
853     if (!GotExtension)
854     {
855         /* Check that we have space to add one */
856         if ((ImpDescName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
857             sizeof(Teb->StaticUnicodeBuffer))
858         {
859             /* No space to add the extension */
860             DbgPrintEx(DPFLTR_LDR_ID,
861                        DPFLTR_ERROR_LEVEL,
862                        "LDR: %s - Dll name missing extension; with extension "
863                        "added the name is too long\n"
864                        "   ImpDescName: (@ %p) \"%wZ\"\n"
865                        "   ImpDescName->Length: %u\n",
866                        __FUNCTION__,
867                        ImpDescName,
868                        ImpDescName,
869                        ImpDescName->Length);
870             return STATUS_NAME_TOO_LONG;
871         }
872 
873         /* Add it. Needs to be null terminated, thus the length check above */
874         (VOID)RtlAppendUnicodeStringToString(ImpDescName,
875                                              &LdrApiDefaultExtension);
876     }
877 
878     /* Check if the SxS Assemblies specify another file */
879     Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
880                                                       ImpDescName,
881                                                       &LdrApiDefaultExtension,
882                                                       NULL,
883                                                       &RedirectedImpDescName,
884                                                       &ImpDescName,
885                                                       NULL,
886                                                       NULL,
887                                                       NULL);
888 
889     /* Check success */
890     if (NT_SUCCESS(Status))
891     {
892         /* Let Ldrp know */
893         RedirectedDll = TRUE;
894     }
895     else if (Status != STATUS_SXS_KEY_NOT_FOUND)
896     {
897         /* Unrecoverable SxS failure */
898         DPRINT1("LDR: RtlDosApplyFileIsolationRedirection_Ustr failed  with status %x for dll %wZ\n", Status, ImpDescName);
899         goto done;
900     }
901 
902     /* Check if it's loaded */
903     if (LdrpCheckForLoadedDll(DllPath,
904                               ImpDescName,
905                               TRUE,
906                               RedirectedDll,
907                               DataTableEntry))
908     {
909         /* It's already existing in the list */
910         *Existing = TRUE;
911         Status = STATUS_SUCCESS;
912         goto done;
913     }
914 
915     /* We're loading it for the first time */
916     *Existing = FALSE;
917 
918     /* Map it */
919     Status = LdrpMapDll(DllPath,
920                         NULL,
921                         ImpDescName->Buffer,
922                         NULL,
923                         TRUE,
924                         RedirectedDll,
925                         DataTableEntry);
926     if (!NT_SUCCESS(Status))
927     {
928         DPRINT1("LDR: LdrpMapDll failed  with status %x for dll %wZ\n", Status, ImpDescName);
929         goto done;
930     }
931 
932     /* Walk its import descriptor table */
933     Status = LdrpWalkImportDescriptor(DllPath,
934                                       *DataTableEntry);
935     if (!NT_SUCCESS(Status))
936     {
937         /* Add it to the in-init-order list in case of failure */
938         InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
939                        &(*DataTableEntry)->InInitializationOrderLinks);
940     }
941 
942 done:
943     RtlFreeUnicodeString(&RedirectedImpDescName);
944 
945     return Status;
946 }
947 
948 NTSTATUS
949 NTAPI
950 LdrpSnapThunk(IN PVOID ExportBase,
951               IN PVOID ImportBase,
952               IN PIMAGE_THUNK_DATA OriginalThunk,
953               IN OUT PIMAGE_THUNK_DATA Thunk,
954               IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
955               IN ULONG ExportSize,
956               IN BOOLEAN Static,
957               IN LPSTR DllName)
958 {
959     BOOLEAN IsOrdinal;
960     USHORT Ordinal;
961     ULONG OriginalOrdinal = 0;
962     PIMAGE_IMPORT_BY_NAME AddressOfData;
963     PULONG NameTable;
964     PUSHORT OrdinalTable;
965     LPSTR ImportName = NULL, DotPosition;
966     USHORT Hint;
967     NTSTATUS Status;
968     ULONG_PTR HardErrorParameters[3];
969     UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
970     ANSI_STRING TempString;
971     ULONG Mask;
972     ULONG Response;
973     PULONG AddressOfFunctions;
974     UNICODE_STRING TempUString;
975     ANSI_STRING ForwarderName;
976     PANSI_STRING ForwardName;
977     PVOID ForwarderHandle;
978     ULONG ForwardOrdinal;
979 
980     /* Check if the snap is by ordinal */
981     if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
982     {
983         /* Get the ordinal number, and its normalized version */
984         OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
985         Ordinal = (USHORT)(OriginalOrdinal - ExportDirectory->Base);
986     }
987     else
988     {
989         /* First get the data VA */
990         AddressOfData = (PIMAGE_IMPORT_BY_NAME)
991                         ((ULONG_PTR)ImportBase +
992                         ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
993 
994         /* Get the name */
995         ImportName = (LPSTR)AddressOfData->Name;
996 
997         /* Now get the VA of the Name and Ordinal Tables */
998         NameTable = (PULONG)((ULONG_PTR)ExportBase +
999                              (ULONG_PTR)ExportDirectory->AddressOfNames);
1000         OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
1001                                  (ULONG_PTR)ExportDirectory->AddressOfNameOrdinals);
1002 
1003         /* Get the hint */
1004         Hint = AddressOfData->Hint;
1005 
1006         /* Try to get a match by using the hint */
1007         if (((ULONG)Hint < ExportDirectory->NumberOfNames) &&
1008              (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
1009         {
1010             /* We got a match, get the Ordinal from the hint */
1011             Ordinal = OrdinalTable[Hint];
1012         }
1013         else
1014         {
1015             /* Well bummer, hint didn't work, do it the long way */
1016             Ordinal = LdrpNameToOrdinal(ImportName,
1017                                         ExportDirectory->NumberOfNames,
1018                                         ExportBase,
1019                                         NameTable,
1020                                         OrdinalTable);
1021         }
1022     }
1023 
1024     /* Check if the ordinal is invalid */
1025     if ((ULONG)Ordinal >= ExportDirectory->NumberOfFunctions)
1026     {
1027 FailurePath:
1028         /* Is this a static snap? */
1029         if (Static)
1030         {
1031             UNICODE_STRING SnapTarget;
1032             PLDR_DATA_TABLE_ENTRY LdrEntry;
1033 
1034             /* What was the module we were searching in */
1035             RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
1036 
1037             /* What was the module we were searching for */
1038             if (LdrpCheckForLoadedDllHandle(ImportBase, &LdrEntry))
1039                 SnapTarget = LdrEntry->BaseDllName;
1040             else
1041                 RtlInitUnicodeString(&SnapTarget, L"Unknown");
1042 
1043             /* Inform the debug log */
1044             if (IsOrdinal)
1045                 DPRINT1("Failed to snap ordinal %Z!0x%x for %wZ\n", &TempString, OriginalOrdinal, &SnapTarget);
1046             else
1047                 DPRINT1("Failed to snap %Z!%s for %wZ\n", &TempString, ImportName, &SnapTarget);
1048 
1049             /* These are critical errors. Setup a string for the DLL name */
1050             RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
1051 
1052             /* Set it as the parameter */
1053             HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
1054             Mask = 2;
1055 
1056             /* Check if we have an ordinal */
1057             if (IsOrdinal)
1058             {
1059                 /* Then set the ordinal as the 1st parameter */
1060                 HardErrorParameters[0] = OriginalOrdinal;
1061             }
1062             else
1063             {
1064                 /* We don't, use the entrypoint. Set up a string for it */
1065                 RtlInitAnsiString(&TempString, ImportName);
1066                 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
1067                                              &TempString,
1068                                              TRUE);
1069 
1070                 /* Set it as the parameter */
1071                 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
1072                 Mask = 3;
1073             }
1074 
1075             /* Raise the error */
1076             NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1077                                          STATUS_ENTRYPOINT_NOT_FOUND,
1078                              2,
1079                              Mask,
1080                              HardErrorParameters,
1081                              OptionOk,
1082                              &Response);
1083 
1084             /* Increase the error count */
1085             if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1086 
1087             /* Free our string */
1088             RtlFreeUnicodeString(&HardErrorDllName);
1089             if (!IsOrdinal)
1090             {
1091                 /* Free our second string. Return entrypoint error */
1092                 RtlFreeUnicodeString(&HardErrorEntryPointName);
1093                 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
1094             }
1095 
1096             /* Return ordinal error */
1097             RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
1098         }
1099         else
1100         {
1101             /* Inform the debug log */
1102             if (IsOrdinal)
1103                 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1104             else
1105                 DPRINT("Non-fatal: Failed to snap %s\n", ImportName);
1106         }
1107 
1108         /* Set this as a bad DLL */
1109         Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
1110 
1111         /* Return the right error code */
1112         Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1113                              STATUS_ENTRYPOINT_NOT_FOUND;
1114     }
1115     else
1116     {
1117         /* The ordinal seems correct, get the AddressOfFunctions VA */
1118         AddressOfFunctions = (PULONG)
1119                              ((ULONG_PTR)ExportBase +
1120                               (ULONG_PTR)ExportDirectory->AddressOfFunctions);
1121 
1122         /* Write the function pointer*/
1123         Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
1124 
1125         /* Make sure it's within the exports */
1126         if ((Thunk->u1.Function > (ULONG_PTR)ExportDirectory) &&
1127             (Thunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
1128         {
1129             /* Get the Import and Forwarder Names */
1130             ImportName = (LPSTR)Thunk->u1.Function;
1131 
1132             DotPosition = strchr(ImportName, '.');
1133             ASSERT(DotPosition != NULL);
1134             if (!DotPosition)
1135                 goto FailurePath;
1136 
1137             ForwarderName.Buffer = ImportName;
1138             ForwarderName.Length = (USHORT)(DotPosition - ImportName);
1139             ForwarderName.MaximumLength = ForwarderName.Length;
1140             Status = RtlAnsiStringToUnicodeString(&TempUString,
1141                                                   &ForwarderName,
1142                                                   TRUE);
1143 
1144             /* Make sure the conversion was OK */
1145             if (NT_SUCCESS(Status))
1146             {
1147                 WCHAR StringBuffer[MAX_PATH];
1148                 UNICODE_STRING StaticString, *RedirectedImportName;
1149                 BOOLEAN Redirected = FALSE;
1150 
1151                 RtlInitEmptyUnicodeString(&StaticString, StringBuffer, sizeof(StringBuffer));
1152 
1153                 /* Check if the SxS Assemblies specify another file */
1154                 Status = RtlDosApplyFileIsolationRedirection_Ustr(TRUE,
1155                                                                   &TempUString,
1156                                                                   &LdrApiDefaultExtension,
1157                                                                   &StaticString,
1158                                                                   NULL,
1159                                                                   &RedirectedImportName,
1160                                                                   NULL,
1161                                                                   NULL,
1162                                                                   NULL);
1163                 if (NT_SUCCESS(Status))
1164                 {
1165                     if (ShowSnaps)
1166                     {
1167                         DPRINT1("LDR: %Z got redirected to %wZ\n", &ForwarderName, RedirectedImportName);
1168                     }
1169                     /* Let Ldrp know */
1170                     Redirected = TRUE;
1171                 }
1172                 else
1173                 {
1174                     RedirectedImportName = &TempUString;
1175                 }
1176 
1177                 /* Load the forwarder */
1178                 Status = LdrpLoadDll(Redirected,
1179                                      NULL,
1180                                      NULL,
1181                                      RedirectedImportName,
1182                                      &ForwarderHandle,
1183                                      FALSE);
1184 
1185                 RtlFreeUnicodeString(&TempUString);
1186             }
1187 
1188             /* If the load or conversion failed, use the failure path */
1189             if (!NT_SUCCESS(Status)) goto FailurePath;
1190 
1191             /* Now set up a name for the actual forwarder dll */
1192             RtlInitAnsiString(&ForwarderName,
1193                               ImportName + ForwarderName.Length + sizeof(CHAR));
1194 
1195             /* Check if it's an ordinal forward */
1196             if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1197             {
1198                 /* We don't have an actual function name */
1199                 ForwardName = NULL;
1200 
1201                 /* Convert the string into an ordinal */
1202                 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1203                                           0,
1204                                           &ForwardOrdinal);
1205 
1206                 /* If this fails, then error out */
1207                 if (!NT_SUCCESS(Status)) goto FailurePath;
1208             }
1209             else
1210             {
1211                 /* Import by name */
1212                 ForwardName = &ForwarderName;
1213                 ForwardOrdinal = 0;
1214             }
1215 
1216             /* Get the pointer */
1217             Status = LdrpGetProcedureAddress(ForwarderHandle,
1218                                              ForwardName,
1219                                              ForwardOrdinal,
1220                                              (PVOID*)&Thunk->u1.Function,
1221                                              FALSE);
1222             /* If this fails, then error out */
1223             if (!NT_SUCCESS(Status)) goto FailurePath;
1224         }
1225         else
1226         {
1227             /* It's not within the exports, let's hope it's valid */
1228             if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1229         }
1230 
1231         /* If we got here, then it's success */
1232         Status = STATUS_SUCCESS;
1233     }
1234 
1235     /* Return status */
1236     return Status;
1237 }
1238 
1239 /* EOF */
1240