xref: /reactos/dll/ntdll/ldr/ldrpe.c (revision b36d9bd9)
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 = LdrpApplyFileNameRedirection(
880         ImpDescName, &LdrApiDefaultExtension, NULL, &RedirectedImpDescName, &ImpDescName, &RedirectedDll);
881 
882     if (!NT_SUCCESS(Status))
883     {
884         /* Unrecoverable SxS failure */
885         DPRINT1("LDR: LdrpApplyFileNameRedirection failed  with status %x for dll %wZ\n", Status, ImpDescName);
886         goto done;
887     }
888 
889     /* Check if it's loaded */
890     if (LdrpCheckForLoadedDll(DllPath,
891                               ImpDescName,
892                               TRUE,
893                               RedirectedDll,
894                               DataTableEntry))
895     {
896         /* It's already existing in the list */
897         *Existing = TRUE;
898         Status = STATUS_SUCCESS;
899         goto done;
900     }
901 
902     /* We're loading it for the first time */
903     *Existing = FALSE;
904 
905     /* Map it */
906     Status = LdrpMapDll(DllPath,
907                         NULL,
908                         ImpDescName->Buffer,
909                         NULL,
910                         TRUE,
911                         RedirectedDll,
912                         DataTableEntry);
913     if (!NT_SUCCESS(Status))
914     {
915         DPRINT1("LDR: LdrpMapDll failed  with status %x for dll %wZ\n", Status, ImpDescName);
916         goto done;
917     }
918 
919     /* Walk its import descriptor table */
920     Status = LdrpWalkImportDescriptor(DllPath,
921                                       *DataTableEntry);
922     if (!NT_SUCCESS(Status))
923     {
924         /* Add it to the in-init-order list in case of failure */
925         InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
926                        &(*DataTableEntry)->InInitializationOrderLinks);
927     }
928 
929 done:
930     RtlFreeUnicodeString(&RedirectedImpDescName);
931 
932     return Status;
933 }
934 
935 NTSTATUS
936 NTAPI
937 LdrpSnapThunk(IN PVOID ExportBase,
938               IN PVOID ImportBase,
939               IN PIMAGE_THUNK_DATA OriginalThunk,
940               IN OUT PIMAGE_THUNK_DATA Thunk,
941               IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,
942               IN ULONG ExportSize,
943               IN BOOLEAN Static,
944               IN LPSTR DllName)
945 {
946     BOOLEAN IsOrdinal;
947     USHORT Ordinal;
948     ULONG OriginalOrdinal = 0;
949     PIMAGE_IMPORT_BY_NAME AddressOfData;
950     PULONG NameTable;
951     PUSHORT OrdinalTable;
952     LPSTR ImportName = NULL, DotPosition;
953     USHORT Hint;
954     NTSTATUS Status;
955     ULONG_PTR HardErrorParameters[3];
956     UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
957     ANSI_STRING TempString;
958     ULONG Mask;
959     ULONG Response;
960     PULONG AddressOfFunctions;
961     UNICODE_STRING TempUString;
962     ANSI_STRING ForwarderName;
963     PANSI_STRING ForwardName;
964     PVOID ForwarderHandle;
965     ULONG ForwardOrdinal;
966 
967     /* Check if the snap is by ordinal */
968     if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
969     {
970         /* Get the ordinal number, and its normalized version */
971         OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
972         Ordinal = (USHORT)(OriginalOrdinal - ExportDirectory->Base);
973     }
974     else
975     {
976         /* First get the data VA */
977         AddressOfData = (PIMAGE_IMPORT_BY_NAME)
978                         ((ULONG_PTR)ImportBase +
979                         ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
980 
981         /* Get the name */
982         ImportName = (LPSTR)AddressOfData->Name;
983 
984         /* Now get the VA of the Name and Ordinal Tables */
985         NameTable = (PULONG)((ULONG_PTR)ExportBase +
986                              (ULONG_PTR)ExportDirectory->AddressOfNames);
987         OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
988                                  (ULONG_PTR)ExportDirectory->AddressOfNameOrdinals);
989 
990         /* Get the hint */
991         Hint = AddressOfData->Hint;
992 
993         /* Try to get a match by using the hint */
994         if (((ULONG)Hint < ExportDirectory->NumberOfNames) &&
995              (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
996         {
997             /* We got a match, get the Ordinal from the hint */
998             Ordinal = OrdinalTable[Hint];
999         }
1000         else
1001         {
1002             /* Well bummer, hint didn't work, do it the long way */
1003             Ordinal = LdrpNameToOrdinal(ImportName,
1004                                         ExportDirectory->NumberOfNames,
1005                                         ExportBase,
1006                                         NameTable,
1007                                         OrdinalTable);
1008         }
1009     }
1010 
1011     /* Check if the ordinal is invalid */
1012     if ((ULONG)Ordinal >= ExportDirectory->NumberOfFunctions)
1013     {
1014 FailurePath:
1015         /* Is this a static snap? */
1016         if (Static)
1017         {
1018             UNICODE_STRING SnapTarget;
1019             PLDR_DATA_TABLE_ENTRY LdrEntry;
1020 
1021             /* What was the module we were searching in */
1022             RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
1023 
1024             /* What was the module we were searching for */
1025             if (LdrpCheckForLoadedDllHandle(ImportBase, &LdrEntry))
1026                 SnapTarget = LdrEntry->BaseDllName;
1027             else
1028                 RtlInitUnicodeString(&SnapTarget, L"Unknown");
1029 
1030             /* Inform the debug log */
1031             if (IsOrdinal)
1032                 DPRINT1("Failed to snap ordinal %Z!0x%x for %wZ\n", &TempString, OriginalOrdinal, &SnapTarget);
1033             else
1034                 DPRINT1("Failed to snap %Z!%s for %wZ\n", &TempString, ImportName, &SnapTarget);
1035 
1036             /* These are critical errors. Setup a string for the DLL name */
1037             RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
1038 
1039             /* Set it as the parameter */
1040             HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
1041             Mask = 2;
1042 
1043             /* Check if we have an ordinal */
1044             if (IsOrdinal)
1045             {
1046                 /* Then set the ordinal as the 1st parameter */
1047                 HardErrorParameters[0] = OriginalOrdinal;
1048             }
1049             else
1050             {
1051                 /* We don't, use the entrypoint. Set up a string for it */
1052                 RtlInitAnsiString(&TempString, ImportName);
1053                 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
1054                                              &TempString,
1055                                              TRUE);
1056 
1057                 /* Set it as the parameter */
1058                 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
1059                 Mask = 3;
1060             }
1061 
1062             /* Raise the error */
1063             NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1064                                          STATUS_ENTRYPOINT_NOT_FOUND,
1065                              2,
1066                              Mask,
1067                              HardErrorParameters,
1068                              OptionOk,
1069                              &Response);
1070 
1071             /* Increase the error count */
1072             if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1073 
1074             /* Free our string */
1075             RtlFreeUnicodeString(&HardErrorDllName);
1076             if (!IsOrdinal)
1077             {
1078                 /* Free our second string. Return entrypoint error */
1079                 RtlFreeUnicodeString(&HardErrorEntryPointName);
1080                 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
1081             }
1082 
1083             /* Return ordinal error */
1084             RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
1085         }
1086         else
1087         {
1088             /* Inform the debug log */
1089             if (IsOrdinal)
1090                 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1091             else
1092                 DPRINT("Non-fatal: Failed to snap %s\n", ImportName);
1093         }
1094 
1095         /* Set this as a bad DLL */
1096         Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
1097 
1098         /* Return the right error code */
1099         Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1100                              STATUS_ENTRYPOINT_NOT_FOUND;
1101     }
1102     else
1103     {
1104         /* The ordinal seems correct, get the AddressOfFunctions VA */
1105         AddressOfFunctions = (PULONG)
1106                              ((ULONG_PTR)ExportBase +
1107                               (ULONG_PTR)ExportDirectory->AddressOfFunctions);
1108 
1109         /* Write the function pointer*/
1110         Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
1111 
1112         /* Make sure it's within the exports */
1113         if ((Thunk->u1.Function > (ULONG_PTR)ExportDirectory) &&
1114             (Thunk->u1.Function < ((ULONG_PTR)ExportDirectory + ExportSize)))
1115         {
1116             /* Get the Import and Forwarder Names */
1117             ImportName = (LPSTR)Thunk->u1.Function;
1118 
1119             DotPosition = strchr(ImportName, '.');
1120             ASSERT(DotPosition != NULL);
1121             if (!DotPosition)
1122                 goto FailurePath;
1123 
1124             ForwarderName.Buffer = ImportName;
1125             ForwarderName.Length = (USHORT)(DotPosition - ImportName);
1126             ForwarderName.MaximumLength = ForwarderName.Length;
1127             Status = RtlAnsiStringToUnicodeString(&TempUString,
1128                                                   &ForwarderName,
1129                                                   TRUE);
1130 
1131             /* Make sure the conversion was OK */
1132             if (NT_SUCCESS(Status))
1133             {
1134                 WCHAR StringBuffer[MAX_PATH];
1135                 UNICODE_STRING StaticString, *RedirectedImportName;
1136                 BOOLEAN Redirected = FALSE;
1137 
1138                 RtlInitEmptyUnicodeString(&StaticString, StringBuffer, sizeof(StringBuffer));
1139 
1140                 /* Check if the SxS Assemblies specify another file */
1141                 Status = LdrpApplyFileNameRedirection(
1142                     &TempUString, &LdrApiDefaultExtension, &StaticString, NULL, &RedirectedImportName, &Redirected);
1143 
1144                 if (NT_SUCCESS(Status) && Redirected)
1145                 {
1146                     if (ShowSnaps)
1147                         DPRINT1("LDR: %Z got redirected to %wZ\n", &ForwarderName, RedirectedImportName);
1148                 }
1149                 else
1150                 {
1151                     RedirectedImportName = &TempUString;
1152                 }
1153 
1154                 /* Load the forwarder */
1155                 Status = LdrpLoadDll(Redirected,
1156                                      NULL,
1157                                      NULL,
1158                                      RedirectedImportName,
1159                                      &ForwarderHandle,
1160                                      FALSE);
1161 
1162                 RtlFreeUnicodeString(&TempUString);
1163             }
1164 
1165             /* If the load or conversion failed, use the failure path */
1166             if (!NT_SUCCESS(Status)) goto FailurePath;
1167 
1168             /* Now set up a name for the actual forwarder dll */
1169             RtlInitAnsiString(&ForwarderName,
1170                               ImportName + ForwarderName.Length + sizeof(CHAR));
1171 
1172             /* Check if it's an ordinal forward */
1173             if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1174             {
1175                 /* We don't have an actual function name */
1176                 ForwardName = NULL;
1177 
1178                 /* Convert the string into an ordinal */
1179                 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1180                                           0,
1181                                           &ForwardOrdinal);
1182 
1183                 /* If this fails, then error out */
1184                 if (!NT_SUCCESS(Status)) goto FailurePath;
1185             }
1186             else
1187             {
1188                 /* Import by name */
1189                 ForwardName = &ForwarderName;
1190                 ForwardOrdinal = 0;
1191             }
1192 
1193             /* Get the pointer */
1194             Status = LdrpGetProcedureAddress(ForwarderHandle,
1195                                              ForwardName,
1196                                              ForwardOrdinal,
1197                                              (PVOID*)&Thunk->u1.Function,
1198                                              FALSE);
1199             /* If this fails, then error out */
1200             if (!NT_SUCCESS(Status)) goto FailurePath;
1201         }
1202         else
1203         {
1204             /* It's not within the exports, let's hope it's valid */
1205             if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1206         }
1207 
1208         /* If we got here, then it's success */
1209         Status = STATUS_SUCCESS;
1210     }
1211 
1212     /* Return status */
1213     return Status;
1214 }
1215 
1216 /* EOF */
1217