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