xref: /reactos/dll/ntdll/ldr/ldrpe.c (revision 24a56f89)
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
LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,IN BOOLEAN EntriesValid)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
LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,IN PLDR_DATA_TABLE_ENTRY LdrEntry,IN PIMAGE_BOUND_IMPORT_DESCRIPTOR * BoundEntryPtr,IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry)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
LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,IN PLDR_DATA_TABLE_ENTRY LdrEntry,IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)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
LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,IN PLDR_DATA_TABLE_ENTRY LdrEntry,IN PIMAGE_IMPORT_DESCRIPTOR * ImportEntry)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
LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,IN PLDR_DATA_TABLE_ENTRY LdrEntry,IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)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
LdrpNameToOrdinal(IN LPSTR ImportName,IN ULONG NumberOfNames,IN PVOID ExportBase,IN PULONG NameTable,IN PUSHORT OrdinalTable)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
LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,IN PLDR_DATA_TABLE_ENTRY LdrEntry)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
LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,IN LPSTR ImportName,OUT PLDR_DATA_TABLE_ENTRY * DataTableEntry,OUT PBOOLEAN Existing)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
LdrpSnapThunk(IN PVOID ExportBase,IN PVOID ImportBase,IN PIMAGE_THUNK_DATA OriginalThunk,IN OUT PIMAGE_THUNK_DATA Thunk,IN PIMAGE_EXPORT_DIRECTORY ExportDirectory,IN ULONG ExportSize,IN BOOLEAN Static,IN LPSTR DllName)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