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