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