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