Create the AHCI branch for Aman's work
[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 PLDR_MANIFEST_PROBER_ROUTINE LdrpManifestProberRoutine;
19 ULONG LdrpNormalSnap;
20
21 /* FUNCTIONS *****************************************************************/
22
23 VOID
24 NTAPI
25 AVrfPageHeapDllNotification(IN PLDR_DATA_TABLE_ENTRY LdrEntry)
26 {
27 /* Check if page heap dll notification is turned on */
28 if (!(RtlpDphGlobalFlags & DPH_FLAG_DLL_NOTIFY))
29 return;
30
31 /* We don't support this flag currently */
32 UNIMPLEMENTED;
33 }
34
35 NTSTATUS
36 NTAPI
37 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,
38 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,
39 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,
40 IN BOOLEAN EntriesValid)
41 {
42 PVOID Iat;
43 NTSTATUS Status;
44 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
45 PIMAGE_NT_HEADERS NtHeader;
46 PIMAGE_SECTION_HEADER SectionHeader;
47 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
48 LPSTR ImportName;
49 ULONG ForwarderChain, i, Rva, OldProtect, IatSize, ExportSize;
50 SIZE_T ImportSize;
51 DPRINT("LdrpSnapIAT(%wZ %wZ %p %u)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid);
52
53 /* Get export directory */
54 ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase,
55 TRUE,
56 IMAGE_DIRECTORY_ENTRY_EXPORT,
57 &ExportSize);
58
59 /* Make sure it has one */
60 if (!ExportDirectory)
61 {
62 /* Fail */
63 DbgPrint("LDR: %wZ doesn't contain an EXPORT table\n",
64 &ExportLdrEntry->BaseDllName);
65 return STATUS_INVALID_IMAGE_FORMAT;
66 }
67
68 /* Get the IAT */
69 Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase,
70 TRUE,
71 IMAGE_DIRECTORY_ENTRY_IAT,
72 &IatSize);
73 ImportSize = IatSize;
74
75 /* Check if we don't have one */
76 if (!Iat)
77 {
78 /* Get the NT Header and the first section */
79 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
80 if (!NtHeader) return STATUS_INVALID_IMAGE_FORMAT;
81 SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
82
83 /* Get the RVA of the import directory */
84 Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
85
86 /* Make sure we got one */
87 if (Rva)
88 {
89 /* Loop all the sections */
90 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
91 {
92 /* Check if we are inside this section */
93 if ((Rva >= SectionHeader->VirtualAddress) &&
94 (Rva < (SectionHeader->VirtualAddress +
95 SectionHeader->SizeOfRawData)))
96 {
97 /* We are, so set the IAT here */
98 Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) +
99 SectionHeader->VirtualAddress);
100
101 /* Set the size */
102 IatSize = SectionHeader->Misc.VirtualSize;
103
104 /* Deal with Watcom and other retarded compilers */
105 if (!IatSize) IatSize = SectionHeader->SizeOfRawData;
106
107 /* Found it, get out */
108 break;
109 }
110
111 /* No match, move to the next section */
112 SectionHeader++;
113 }
114 }
115
116 /* If we still don't have an IAT, that's bad */
117 if (!Iat)
118 {
119 /* Fail */
120 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Image Base %p)\n",
121 &ImportLdrEntry->BaseDllName,
122 ImportLdrEntry->DllBase);
123 return STATUS_INVALID_IMAGE_FORMAT;
124 }
125
126 /* Set the right size */
127 ImportSize = IatSize;
128 }
129
130 /* Unprotect the IAT */
131 Status = NtProtectVirtualMemory(NtCurrentProcess(),
132 &Iat,
133 &ImportSize,
134 PAGE_READWRITE,
135 &OldProtect);
136 if (!NT_SUCCESS(Status))
137 {
138 /* Fail */
139 DbgPrint("LDR: Unable to unprotect IAT for %wZ (Status %x)\n",
140 &ImportLdrEntry->BaseDllName,
141 Status);
142 return Status;
143 }
144
145 /* Check if the Thunks are already valid */
146 if (EntriesValid)
147 {
148 /* We'll only do forwarders. Get the import name */
149 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name);
150
151 /* Get the list of 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->InInitializationOrderLinks);
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->InInitializationOrderLinks);
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->InInitializationOrderLinks);
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, Status2;
690 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
691 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
692 ULONG BoundSize, IatSize;
693
694 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry->BaseDllName, LdrEntry, DllPath);
695
696 /* Set up the Act Ctx */
697 RtlZeroMemory(&ActCtx, sizeof(ActCtx));
698 ActCtx.Size = sizeof(ActCtx);
699 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
700
701 /* Check if we have a manifest prober routine */
702 if (LdrpManifestProberRoutine)
703 {
704 /* Probe the DLL for its manifest. Some details are omitted */
705 Status2 = LdrpManifestProberRoutine(LdrEntry->DllBase, LdrEntry->FullDllName.Buffer, &LdrEntry->EntryPointActivationContext);
706
707 if (!NT_SUCCESS(Status2) &&
708 Status2 != STATUS_NO_SUCH_FILE &&
709 Status2 != STATUS_RESOURCE_DATA_NOT_FOUND &&
710 Status2 != STATUS_RESOURCE_TYPE_NOT_FOUND &&
711 Status2 != STATUS_RESOURCE_NAME_NOT_FOUND &&
712 Status2 != STATUS_RESOURCE_LANG_NOT_FOUND)
713 {
714 /* Some serious issue */
715 //Status = Status2; // FIXME: Ignore that error for now
716 DbgPrintEx(DPFLTR_SXS_ID,
717 DPFLTR_WARNING_LEVEL,
718 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
719 "manifest, ntstatus = 0x%08lx\n",
720 &LdrEntry->FullDllName, Status);
721 }
722 }
723
724 /* Check if we failed above */
725 if (!NT_SUCCESS(Status)) return Status;
726
727 /* Get the Active ActCtx */
728 if (!LdrEntry->EntryPointActivationContext)
729 {
730 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
731
732 if (!NT_SUCCESS(Status))
733 {
734 /* Exit */
735 DbgPrintEx(DPFLTR_SXS_ID,
736 DPFLTR_WARNING_LEVEL,
737 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
738 "0x%08lx\n",
739 Status);
740 return Status;
741 }
742 }
743
744 /* Activate the ActCtx */
745 RtlActivateActivationContextUnsafeFast(&ActCtx,
746 LdrEntry->EntryPointActivationContext);
747
748 /* Check if we were redirected */
749 if (!(LdrEntry->Flags & LDRP_REDIRECTED))
750 {
751 /* Get the Bound IAT */
752 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
753 TRUE,
754 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
755 &BoundSize);
756 }
757
758 /* Get the regular IAT, for fallback */
759 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
760 TRUE,
761 IMAGE_DIRECTORY_ENTRY_IMPORT,
762 &IatSize);
763
764 /* Check if we got at least one */
765 if ((BoundEntry) || (ImportEntry))
766 {
767 /* Do we have a Bound IAT */
768 if (BoundEntry)
769 {
770 /* Handle the descriptor */
771 Status = LdrpHandleNewFormatImportDescriptors(DllPath,
772 LdrEntry,
773 BoundEntry);
774 }
775 else
776 {
777 /* Handle the descriptor */
778 Status = LdrpHandleOldFormatImportDescriptors(DllPath,
779 LdrEntry,
780 ImportEntry);
781 }
782
783 /* Check the status of the handlers */
784 if (NT_SUCCESS(Status))
785 {
786 /* Check for Per-DLL Heap Tagging */
787 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
788 {
789 /* FIXME */
790 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
791 }
792
793 /* Check if Page Heap was enabled */
794 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
795 {
796 /* Initialize target DLL */
797 AVrfPageHeapDllNotification(LdrEntry);
798 }
799
800 /* Check if Application Verifier was enabled */
801 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
802 {
803 /* FIXME */
804 DPRINT1("We don't support Application Verifier yet!\n");
805 }
806
807 /* Just to be safe */
808 Status = STATUS_SUCCESS;
809 }
810 }
811
812 /* Release the activation context */
813 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
814
815 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry->BaseDllName, LdrEntry);
816
817 /* Return status */
818 return Status;
819 }
820
821 /* FIXME: This function is missing SxS support and has wrong prototype */
822 NTSTATUS
823 NTAPI
824 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
825 IN LPSTR ImportName,
826 IN PVOID DllBase,
827 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
828 OUT PBOOLEAN Existing)
829 {
830 ANSI_STRING AnsiString;
831 PUNICODE_STRING ImpDescName;
832 NTSTATUS Status;
833 PPEB Peb = RtlGetCurrentPeb();
834 PTEB Teb = NtCurrentTeb();
835
836 DPRINT("LdrpLoadImportModule('%s' %p %p %p '%S')\n", ImportName, DllBase, DataTableEntry, Existing, DllPath);
837
838 /* Convert import descriptor name to unicode string */
839 ImpDescName = &Teb->StaticUnicodeString;
840 RtlInitAnsiString(&AnsiString, ImportName);
841 Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE);
842 if (!NT_SUCCESS(Status)) return Status;
843
844 /* Check if it's loaded */
845 if (LdrpCheckForLoadedDll(DllPath,
846 ImpDescName,
847 TRUE,
848 FALSE,
849 DataTableEntry))
850 {
851 /* It's already existing in the list */
852 *Existing = TRUE;
853 return STATUS_SUCCESS;
854 }
855
856 /* We're loading it for the first time */
857 *Existing = FALSE;
858
859 #if 0
860 /* Load manifest */
861 {
862 ACTCTX_SECTION_KEYED_DATA data;
863 NTSTATUS status;
864
865 //DPRINT1("find_actctx_dll for %S\n", fullname);
866 //RtlInitUnicodeString(&nameW, libname);
867 data.cbSize = sizeof(data);
868 status = RtlFindActivationContextSectionString(
869 FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
870 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
871 ImpDescName,
872 &data);
873 //if (status != STATUS_SUCCESS) return status;
874 DPRINT1("Status: 0x%08X\n", status);
875
876 if (NT_SUCCESS(status))
877 {
878 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
879 SIZE_T needed, size = 1024;
880
881 for (;;)
882 {
883 if (!(info = RtlAllocateHeap(RtlGetProcessHeap(), 0, size)))
884 {
885 status = STATUS_NO_MEMORY;
886 goto done;
887 }
888 status = RtlQueryInformationActivationContext(0, data.hActCtx, &data.ulAssemblyRosterIndex,
889 AssemblyDetailedInformationInActivationContext,
890 info, size, &needed);
891 if (status == STATUS_SUCCESS) break;
892 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
893 RtlFreeHeap(RtlGetProcessHeap(), 0, info);
894 size = needed;
895 }
896
897 DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath);
898 DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName);
899 }
900 }
901 done:
902 #endif
903
904 /* Map it */
905 Status = LdrpMapDll(DllPath,
906 NULL,
907 ImpDescName->Buffer,
908 NULL,
909 TRUE,
910 FALSE,
911 DataTableEntry);
912
913 if (!NT_SUCCESS(Status)) return Status;
914
915 /* Walk its import descriptor table */
916 Status = LdrpWalkImportDescriptor(DllPath,
917 *DataTableEntry);
918 if (!NT_SUCCESS(Status))
919 {
920 /* Add it to the in-init-order list in case of failure */
921 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
922 &(*DataTableEntry)->InInitializationOrderLinks);
923 }
924
925 return Status;
926 }
927
928 NTSTATUS
929 NTAPI
930 LdrpSnapThunk(IN PVOID ExportBase,
931 IN PVOID ImportBase,
932 IN PIMAGE_THUNK_DATA OriginalThunk,
933 IN OUT PIMAGE_THUNK_DATA Thunk,
934 IN PIMAGE_EXPORT_DIRECTORY ExportEntry,
935 IN ULONG ExportSize,
936 IN BOOLEAN Static,
937 IN LPSTR DllName)
938 {
939 BOOLEAN IsOrdinal;
940 USHORT Ordinal;
941 ULONG OriginalOrdinal = 0;
942 PIMAGE_IMPORT_BY_NAME AddressOfData;
943 PULONG NameTable;
944 PUSHORT OrdinalTable;
945 LPSTR ImportName = NULL;
946 USHORT Hint;
947 NTSTATUS Status;
948 ULONG_PTR HardErrorParameters[3];
949 UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
950 ANSI_STRING TempString;
951 ULONG Mask;
952 ULONG Response;
953 PULONG AddressOfFunctions;
954 UNICODE_STRING TempUString;
955 ANSI_STRING ForwarderName;
956 PANSI_STRING ForwardName;
957 PVOID ForwarderHandle;
958 ULONG ForwardOrdinal;
959
960 /* Check if the snap is by ordinal */
961 if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
962 {
963 /* Get the ordinal number, and its normalized version */
964 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
965 Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
966 }
967 else
968 {
969 /* First get the data VA */
970 AddressOfData = (PIMAGE_IMPORT_BY_NAME)
971 ((ULONG_PTR)ImportBase +
972 ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
973
974 /* Get the name */
975 ImportName = (LPSTR)AddressOfData->Name;
976
977 /* Now get the VA of the Name and Ordinal Tables */
978 NameTable = (PULONG)((ULONG_PTR)ExportBase +
979 (ULONG_PTR)ExportEntry->AddressOfNames);
980 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
981 (ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
982
983 /* Get the hint */
984 Hint = AddressOfData->Hint;
985
986 /* Try to get a match by using the hint */
987 if (((ULONG)Hint < ExportEntry->NumberOfNames) &&
988 (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
989 {
990 /* We got a match, get the Ordinal from the hint */
991 Ordinal = OrdinalTable[Hint];
992 }
993 else
994 {
995 /* Well bummer, hint didn't work, do it the long way */
996 Ordinal = LdrpNameToOrdinal(ImportName,
997 ExportEntry->NumberOfNames,
998 ExportBase,
999 NameTable,
1000 OrdinalTable);
1001 }
1002 }
1003
1004 /* Check if the ordinal is invalid */
1005 if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
1006 {
1007 FailurePath:
1008 /* Is this a static snap? */
1009 if (Static)
1010 {
1011 /* Inform the debug log */
1012 if (IsOrdinal)
1013 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1014 else
1015 DPRINT1("Failed to snap %s\n", ImportName);
1016
1017 /* These are critical errors. Setup a string for the DLL name */
1018 RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
1019 RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
1020
1021 /* Set it as the parameter */
1022 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
1023 Mask = 2;
1024
1025 /* Check if we have an ordinal */
1026 if (IsOrdinal)
1027 {
1028 /* Then set the ordinal as the 1st parameter */
1029 HardErrorParameters[0] = OriginalOrdinal;
1030 }
1031 else
1032 {
1033 /* We don't, use the entrypoint. Set up a string for it */
1034 RtlInitAnsiString(&TempString, ImportName);
1035 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
1036 &TempString,
1037 TRUE);
1038
1039 /* Set it as the parameter */
1040 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
1041 Mask = 3;
1042 }
1043
1044 /* Raise the error */
1045 NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1046 STATUS_ENTRYPOINT_NOT_FOUND,
1047 2,
1048 Mask,
1049 HardErrorParameters,
1050 OptionOk,
1051 &Response);
1052
1053 /* Increase the error count */
1054 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1055
1056 /* Free our string */
1057 RtlFreeUnicodeString(&HardErrorDllName);
1058 if (!IsOrdinal)
1059 {
1060 /* Free our second string. Return entrypoint error */
1061 RtlFreeUnicodeString(&HardErrorEntryPointName);
1062 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
1063 }
1064
1065 /* Return ordinal error */
1066 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
1067 }
1068 else
1069 {
1070 /* Inform the debug log */
1071 if (IsOrdinal)
1072 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1073 else
1074 DPRINT("Non-fatal: Failed to snap %s\n", ImportName);
1075 }
1076
1077 /* Set this as a bad DLL */
1078 Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
1079
1080 /* Return the right error code */
1081 Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1082 STATUS_ENTRYPOINT_NOT_FOUND;
1083 }
1084 else
1085 {
1086 /* The ordinal seems correct, get the AddressOfFunctions VA */
1087 AddressOfFunctions = (PULONG)
1088 ((ULONG_PTR)ExportBase +
1089 (ULONG_PTR)ExportEntry->AddressOfFunctions);
1090
1091 /* Write the function pointer*/
1092 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
1093
1094 /* Make sure it's within the exports */
1095 if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) &&
1096 (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
1097 {
1098 /* Get the Import and Forwarder Names */
1099 ImportName = (LPSTR)Thunk->u1.Function;
1100 ForwarderName.Buffer = ImportName;
1101 ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);
1102 ForwarderName.MaximumLength = ForwarderName.Length;
1103 Status = RtlAnsiStringToUnicodeString(&TempUString,
1104 &ForwarderName,
1105 TRUE);
1106
1107 /* Make sure the conversion was OK */
1108 if (NT_SUCCESS(Status))
1109 {
1110 /* Load the forwarder, free the temp string */
1111 Status = LdrpLoadDll(FALSE,
1112 NULL,
1113 NULL,
1114 &TempUString,
1115 &ForwarderHandle,
1116 FALSE);
1117 RtlFreeUnicodeString(&TempUString);
1118 }
1119
1120 /* If the load or conversion failed, use the failure path */
1121 if (!NT_SUCCESS(Status)) goto FailurePath;
1122
1123 /* Now set up a name for the actual forwarder dll */
1124 RtlInitAnsiString(&ForwarderName,
1125 ImportName + ForwarderName.Length + sizeof(CHAR));
1126
1127 /* Check if it's an ordinal forward */
1128 if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1129 {
1130 /* We don't have an actual function name */
1131 ForwardName = NULL;
1132
1133 /* Convert the string into an ordinal */
1134 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1135 0,
1136 &ForwardOrdinal);
1137
1138 /* If this fails, then error out */
1139 if (!NT_SUCCESS(Status)) goto FailurePath;
1140 }
1141 else
1142 {
1143 /* Import by name */
1144 ForwardName = &ForwarderName;
1145 }
1146
1147 /* Get the pointer */
1148 Status = LdrpGetProcedureAddress(ForwarderHandle,
1149 ForwardName,
1150 ForwardOrdinal,
1151 (PVOID*)&Thunk->u1.Function,
1152 FALSE);
1153 /* If this fails, then error out */
1154 if (!NT_SUCCESS(Status)) goto FailurePath;
1155 }
1156 else
1157 {
1158 /* It's not within the exports, let's hope it's valid */
1159 if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1160 }
1161
1162 /* If we got here, then it's success */
1163 Status = STATUS_SUCCESS;
1164 }
1165
1166 /* Return status */
1167 return Status;
1168 }
1169
1170 /* EOF */