Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[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 forwarders */
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 message */
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 &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->InInitializationOrderLinks);
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 &ForwarderLdrEntry,
374 &AlreadyLoaded);
375 if (NT_SUCCESS(Status))
376 {
377 /* Loaded it, was it already loaded? */
378 if (!AlreadyLoaded)
379 {
380 /* Add it to our list */
381 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
382 &ForwarderLdrEntry->InInitializationOrderLinks);
383 }
384 }
385
386 /* Check if the Bound Entry is now invalid */
387 if (!(NT_SUCCESS(Status)) ||
388 (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) ||
389 (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
390 {
391 /* Show debug message */
392 if (ShowSnaps)
393 {
394 DPRINT1("LDR: %wZ has stale binding to %s\n",
395 &LdrEntry->BaseDllName,
396 ForwarderName);
397 }
398
399 /* Remember it's become stale */
400 Stale = TRUE;
401 }
402 else
403 {
404 /* Show debug message */
405 if (ShowSnaps)
406 {
407 DPRINT1("LDR: %wZ has correct binding to %s\n",
408 &LdrEntry->BaseDllName,
409 ForwarderName);
410 }
411
412 /* Remember it's valid */
413 Stale = FALSE;
414 }
415
416 /* Move to the next one */
417 ForwarderEntry++;
418 }
419
420 /* Set the next bound entry to the forwarder */
421 FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry;
422
423 /* Check if the binding was stale */
424 if (Stale)
425 {
426 /* It was, so find the IAT entry for it */
427 ++LdrpNormalSnap;
428 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
429 TRUE,
430 IMAGE_DIRECTORY_ENTRY_IMPORT,
431 &IatSize);
432
433 /* Make sure it has a name */
434 while (ImportEntry->Name)
435 {
436 /* Get the name */
437 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
438
439 /* Compare it */
440 if (!_stricmp(ImportName, BoundImportName)) break;
441
442 /* Move to next entry */
443 ImportEntry++;
444 }
445
446 /* If we didn't find a name, fail */
447 if (!ImportEntry->Name)
448 {
449 /* Show debug message */
450 if (ShowSnaps)
451 {
452 DPRINT1("LDR: LdrpWalkImportTable - failing with"
453 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
454 }
455
456 /* Return error */
457 Status = STATUS_OBJECT_NAME_INVALID;
458 goto Quickie;
459 }
460
461 /* Show debug message */
462 if (ShowSnaps)
463 {
464 DPRINT1("LDR: Stale Bind %s from %wZ\n",
465 ImportName,
466 &LdrEntry->BaseDllName);
467 }
468
469 /* Snap the IAT Entry*/
470 Status = LdrpSnapIAT(DllLdrEntry,
471 LdrEntry,
472 ImportEntry,
473 FALSE);
474
475 /* Make sure we didn't fail */
476 if (!NT_SUCCESS(Status))
477 {
478 /* Show debug message */
479 if (ShowSnaps)
480 {
481 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
482 &LdrEntry->BaseDllName,
483 BoundImportName,
484 Status);
485 }
486
487 /* Return */
488 goto Quickie;
489 }
490 }
491
492 /* All done */
493 Status = STATUS_SUCCESS;
494
495 Quickie:
496 /* Write where we are now and return */
497 *BoundEntryPtr = FirstEntry;
498 return Status;
499 }
500
501 NTSTATUS
502 NTAPI
503 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
504 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
505 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)
506 {
507 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry;
508 NTSTATUS Status;
509
510 /* Make sure we have a name */
511 while (BoundEntry->OffsetModuleName)
512 {
513 /* Parse this descriptor */
514 Status = LdrpHandleOneNewFormatImportDescriptor(DllPath,
515 LdrEntry,
516 &BoundEntry,
517 FirstEntry);
518 if (!NT_SUCCESS(Status)) return Status;
519 }
520
521 /* Done */
522 return STATUS_SUCCESS;
523 }
524
525 NTSTATUS
526 NTAPI
527 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
528 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
529 IN PIMAGE_IMPORT_DESCRIPTOR *ImportEntry)
530 {
531 LPSTR ImportName;
532 NTSTATUS Status;
533 BOOLEAN AlreadyLoaded = FALSE;
534 PLDR_DATA_TABLE_ENTRY DllLdrEntry;
535 PIMAGE_THUNK_DATA FirstThunk;
536 PPEB Peb = NtCurrentPeb();
537
538 /* Get the import name's VA */
539 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + (*ImportEntry)->Name);
540
541 /* Get the first thunk */
542 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase +
543 (*ImportEntry)->FirstThunk);
544
545 /* Make sure it's valid */
546 if (!FirstThunk->u1.Function) goto SkipEntry;
547
548 /* Show debug message */
549 if (ShowSnaps)
550 {
551 DPRINT1("LDR: %s used by %wZ\n",
552 ImportName,
553 &LdrEntry->BaseDllName);
554 }
555
556 /* Load the module associated to it */
557 Status = LdrpLoadImportModule(DllPath,
558 ImportName,
559 &DllLdrEntry,
560 &AlreadyLoaded);
561 if (!NT_SUCCESS(Status))
562 {
563 /* Fail */
564 if (ShowSnaps)
565 {
566 DbgPrint("LDR: LdrpWalkImportTable - LdrpLoadImportModule failed "
567 "on import %s with status %x\n",
568 ImportName,
569 Status);
570 }
571
572 /* Return */
573 return Status;
574 }
575
576 /* Show debug message */
577 if (ShowSnaps)
578 {
579 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
580 &LdrEntry->BaseDllName,
581 ImportName);
582 }
583
584 /* Check if it wasn't already loaded */
585 ++LdrpNormalSnap;
586 if (!AlreadyLoaded)
587 {
588 /* Add the DLL to our list */
589 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
590 &DllLdrEntry->InInitializationOrderLinks);
591 }
592
593 /* Now snap the IAT Entry */
594 Status = LdrpSnapIAT(DllLdrEntry, LdrEntry, *ImportEntry, FALSE);
595 if (!NT_SUCCESS(Status))
596 {
597 /* Fail */
598 if (ShowSnaps)
599 {
600 DbgPrint("LDR: LdrpWalkImportTable - LdrpSnapIAT #2 failed with "
601 "status %x\n",
602 Status);
603 }
604
605 /* Return */
606 return Status;
607 }
608
609 SkipEntry:
610 /* Move on */
611 (*ImportEntry)++;
612 return STATUS_SUCCESS;
613 }
614
615 NTSTATUS
616 NTAPI
617 LdrpHandleOldFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
618 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
619 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
620 {
621 NTSTATUS Status;
622
623 /* Check for Name and Thunk */
624 while ((ImportEntry->Name) && (ImportEntry->FirstThunk))
625 {
626 /* Parse this descriptor */
627 Status = LdrpHandleOneOldFormatImportDescriptor(DllPath,
628 LdrEntry,
629 &ImportEntry);
630 if (!NT_SUCCESS(Status)) return Status;
631 }
632
633 /* Done */
634 return STATUS_SUCCESS;
635 }
636
637 USHORT
638 NTAPI
639 LdrpNameToOrdinal(IN LPSTR ImportName,
640 IN ULONG NumberOfNames,
641 IN PVOID ExportBase,
642 IN PULONG NameTable,
643 IN PUSHORT OrdinalTable)
644 {
645 LONG Start, End, Next, CmpResult;
646
647 /* Use classical binary search to find the ordinal */
648 Start = Next = 0;
649 End = NumberOfNames - 1;
650 while (End >= Start)
651 {
652 /* Next will be exactly between Start and End */
653 Next = (Start + End) >> 1;
654
655 /* Compare this name with the one we need to find */
656 CmpResult = strcmp(ImportName, (PCHAR)((ULONG_PTR)ExportBase + NameTable[Next]));
657
658 /* We found our entry if result is 0 */
659 if (!CmpResult) break;
660
661 /* We didn't find, update our range then */
662 if (CmpResult < 0)
663 {
664 End = Next - 1;
665 }
666 else if (CmpResult > 0)
667 {
668 Start = Next + 1;
669 }
670 }
671
672 /* If end is before start, then the search failed */
673 if (End < Start) return -1;
674
675 /* Return found name */
676 return OrdinalTable[Next];
677 }
678
679 NTSTATUS
680 NTAPI
681 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
682 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
683 {
684 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
685 PPEB Peb = NtCurrentPeb();
686 NTSTATUS Status = STATUS_SUCCESS, Status2;
687 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
688 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
689 ULONG BoundSize, IatSize;
690
691 DPRINT("LdrpWalkImportDescriptor - BEGIN (%wZ %p '%S')\n", &LdrEntry->BaseDllName, LdrEntry, DllPath);
692
693 /* Set up the Act Ctx */
694 RtlZeroMemory(&ActCtx, sizeof(ActCtx));
695 ActCtx.Size = sizeof(ActCtx);
696 ActCtx.Format = RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_FORMAT_WHISTLER;
697
698 /* Check if we have a manifest prober routine */
699 if (LdrpManifestProberRoutine)
700 {
701 /* Probe the DLL for its manifest. Some details are omitted */
702 Status2 = LdrpManifestProberRoutine(LdrEntry->DllBase, LdrEntry->FullDllName.Buffer, &LdrEntry->EntryPointActivationContext);
703
704 if (!NT_SUCCESS(Status2) &&
705 Status2 != STATUS_NO_SUCH_FILE &&
706 Status2 != STATUS_RESOURCE_DATA_NOT_FOUND &&
707 Status2 != STATUS_RESOURCE_TYPE_NOT_FOUND &&
708 Status2 != STATUS_RESOURCE_NAME_NOT_FOUND &&
709 Status2 != STATUS_RESOURCE_LANG_NOT_FOUND)
710 {
711 /* Some serious issue */
712 //Status = Status2; // FIXME: Ignore that error for now
713 DbgPrintEx(DPFLTR_SXS_ID,
714 DPFLTR_WARNING_LEVEL,
715 "LDR: LdrpWalkImportDescriptor() failed to probe %wZ for its "
716 "manifest, ntstatus = 0x%08lx\n",
717 &LdrEntry->FullDllName, Status);
718 }
719 }
720
721 /* Check if we failed above */
722 if (!NT_SUCCESS(Status)) return Status;
723
724 /* Get the Active ActCtx */
725 if (!LdrEntry->EntryPointActivationContext)
726 {
727 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
728
729 if (!NT_SUCCESS(Status))
730 {
731 /* Exit */
732 DbgPrintEx(DPFLTR_SXS_ID,
733 DPFLTR_WARNING_LEVEL,
734 "LDR: RtlGetActiveActivationContext() failed; ntstatus = "
735 "0x%08lx\n",
736 Status);
737 return Status;
738 }
739 }
740
741 /* Activate the ActCtx */
742 RtlActivateActivationContextUnsafeFast(&ActCtx,
743 LdrEntry->EntryPointActivationContext);
744
745 /* Check if we were redirected */
746 if (!(LdrEntry->Flags & LDRP_REDIRECTED))
747 {
748 /* Get the Bound IAT */
749 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
750 TRUE,
751 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
752 &BoundSize);
753 }
754
755 /* Get the regular IAT, for fallback */
756 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
757 TRUE,
758 IMAGE_DIRECTORY_ENTRY_IMPORT,
759 &IatSize);
760
761 /* Check if we got at least one */
762 if ((BoundEntry) || (ImportEntry))
763 {
764 /* Do we have a Bound IAT */
765 if (BoundEntry)
766 {
767 /* Handle the descriptor */
768 Status = LdrpHandleNewFormatImportDescriptors(DllPath,
769 LdrEntry,
770 BoundEntry);
771 }
772 else
773 {
774 /* Handle the descriptor */
775 Status = LdrpHandleOldFormatImportDescriptors(DllPath,
776 LdrEntry,
777 ImportEntry);
778 }
779
780 /* Check the status of the handlers */
781 if (NT_SUCCESS(Status))
782 {
783 /* Check for Per-DLL Heap Tagging */
784 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
785 {
786 /* FIXME */
787 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
788 }
789
790 /* Check if Page Heap was enabled */
791 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
792 {
793 /* Initialize target DLL */
794 AVrfPageHeapDllNotification(LdrEntry);
795 }
796
797 /* Check if Application Verifier was enabled */
798 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
799 {
800 /* FIXME */
801 DPRINT1("We don't support Application Verifier yet!\n");
802 }
803
804 /* Just to be safe */
805 Status = STATUS_SUCCESS;
806 }
807 }
808
809 /* Release the activation context */
810 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
811
812 DPRINT("LdrpWalkImportDescriptor - END (%wZ %p)\n", &LdrEntry->BaseDllName, LdrEntry);
813
814 /* Return status */
815 return Status;
816 }
817
818 /* FIXME: This function is missing SxS support */
819 NTSTATUS
820 NTAPI
821 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
822 IN LPSTR ImportName,
823 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
824 OUT PBOOLEAN Existing)
825 {
826 ANSI_STRING AnsiString;
827 PUNICODE_STRING ImpDescName;
828 const WCHAR *p;
829 BOOLEAN GotExtension;
830 WCHAR c;
831 NTSTATUS Status;
832 PPEB Peb = RtlGetCurrentPeb();
833 PTEB Teb = NtCurrentTeb();
834
835 DPRINT("LdrpLoadImportModule('%S' '%s' %p %p)\n", DllPath, ImportName, DataTableEntry, Existing);
836
837 /* Convert import descriptor name to unicode string */
838 ImpDescName = &Teb->StaticUnicodeString;
839 RtlInitAnsiString(&AnsiString, ImportName);
840 Status = RtlAnsiStringToUnicodeString(ImpDescName, &AnsiString, FALSE);
841 if (!NT_SUCCESS(Status)) return Status;
842
843 /* Find the extension, if present */
844 p = ImpDescName->Buffer + ImpDescName->Length / sizeof(WCHAR) - 1;
845 GotExtension = FALSE;
846 while (p >= ImpDescName->Buffer)
847 {
848 c = *p--;
849 if (c == L'.')
850 {
851 GotExtension = TRUE;
852 break;
853 }
854 else if (c == L'\\')
855 {
856 break;
857 }
858 }
859
860 /* If no extension was found, add the default extension */
861 if (!GotExtension)
862 {
863 /* Check that we have space to add one */
864 if ((ImpDescName->Length + LdrApiDefaultExtension.Length + sizeof(UNICODE_NULL)) >=
865 sizeof(Teb->StaticUnicodeBuffer))
866 {
867 /* No space to add the extension */
868 DbgPrintEx(DPFLTR_LDR_ID,
869 DPFLTR_ERROR_LEVEL,
870 "LDR: %s - Dll name missing extension; with extension "
871 "added the name is too long\n"
872 " ImpDescName: (@ %p) \"%wZ\"\n"
873 " ImpDescName->Length: %u\n",
874 __FUNCTION__,
875 ImpDescName,
876 ImpDescName,
877 ImpDescName->Length);
878 return STATUS_NAME_TOO_LONG;
879 }
880
881 /* Add it. Needs to be null terminated, thus the length check above */
882 (VOID)RtlAppendUnicodeStringToString(ImpDescName,
883 &LdrApiDefaultExtension);
884 }
885
886 /* Check if it's loaded */
887 if (LdrpCheckForLoadedDll(DllPath,
888 ImpDescName,
889 TRUE,
890 FALSE,
891 DataTableEntry))
892 {
893 /* It's already existing in the list */
894 *Existing = TRUE;
895 return STATUS_SUCCESS;
896 }
897
898 /* We're loading it for the first time */
899 *Existing = FALSE;
900
901 #if 0
902 /* Load manifest */
903 {
904 ACTCTX_SECTION_KEYED_DATA data;
905 NTSTATUS status;
906
907 //DPRINT1("find_actctx_dll for %S\n", fullname);
908 //RtlInitUnicodeString(&nameW, libname);
909 data.cbSize = sizeof(data);
910 status = RtlFindActivationContextSectionString(
911 FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
912 ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
913 ImpDescName,
914 &data);
915 //if (status != STATUS_SUCCESS) return status;
916 DPRINT1("Status: 0x%08X\n", status);
917
918 if (NT_SUCCESS(status))
919 {
920 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info;
921 SIZE_T needed, size = 1024;
922
923 for (;;)
924 {
925 if (!(info = RtlAllocateHeap(RtlGetProcessHeap(), 0, size)))
926 {
927 status = STATUS_NO_MEMORY;
928 goto done;
929 }
930 status = RtlQueryInformationActivationContext(0, data.hActCtx, &data.ulAssemblyRosterIndex,
931 AssemblyDetailedInformationInActivationContext,
932 info, size, &needed);
933 if (status == STATUS_SUCCESS) break;
934 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
935 RtlFreeHeap(RtlGetProcessHeap(), 0, info);
936 size = needed;
937 }
938
939 DPRINT("manifestpath === %S\n", info->lpAssemblyManifestPath);
940 DPRINT("DirectoryName === %S\n", info->lpAssemblyDirectoryName);
941 }
942 }
943 done:
944 #endif
945
946 /* Map it */
947 Status = LdrpMapDll(DllPath,
948 NULL,
949 ImpDescName->Buffer,
950 NULL,
951 TRUE,
952 FALSE,
953 DataTableEntry);
954
955 if (!NT_SUCCESS(Status)) return Status;
956
957 /* Walk its import descriptor table */
958 Status = LdrpWalkImportDescriptor(DllPath,
959 *DataTableEntry);
960 if (!NT_SUCCESS(Status))
961 {
962 /* Add it to the in-init-order list in case of failure */
963 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
964 &(*DataTableEntry)->InInitializationOrderLinks);
965 }
966
967 return Status;
968 }
969
970 NTSTATUS
971 NTAPI
972 LdrpSnapThunk(IN PVOID ExportBase,
973 IN PVOID ImportBase,
974 IN PIMAGE_THUNK_DATA OriginalThunk,
975 IN OUT PIMAGE_THUNK_DATA Thunk,
976 IN PIMAGE_EXPORT_DIRECTORY ExportEntry,
977 IN ULONG ExportSize,
978 IN BOOLEAN Static,
979 IN LPSTR DllName)
980 {
981 BOOLEAN IsOrdinal;
982 USHORT Ordinal;
983 ULONG OriginalOrdinal = 0;
984 PIMAGE_IMPORT_BY_NAME AddressOfData;
985 PULONG NameTable;
986 PUSHORT OrdinalTable;
987 LPSTR ImportName = NULL;
988 USHORT Hint;
989 NTSTATUS Status;
990 ULONG_PTR HardErrorParameters[3];
991 UNICODE_STRING HardErrorDllName, HardErrorEntryPointName;
992 ANSI_STRING TempString;
993 ULONG Mask;
994 ULONG Response;
995 PULONG AddressOfFunctions;
996 UNICODE_STRING TempUString;
997 ANSI_STRING ForwarderName;
998 PANSI_STRING ForwardName;
999 PVOID ForwarderHandle;
1000 ULONG ForwardOrdinal;
1001
1002 /* Check if the snap is by ordinal */
1003 if ((IsOrdinal = IMAGE_SNAP_BY_ORDINAL(OriginalThunk->u1.Ordinal)))
1004 {
1005 /* Get the ordinal number, and its normalized version */
1006 OriginalOrdinal = IMAGE_ORDINAL(OriginalThunk->u1.Ordinal);
1007 Ordinal = (USHORT)(OriginalOrdinal - ExportEntry->Base);
1008 }
1009 else
1010 {
1011 /* First get the data VA */
1012 AddressOfData = (PIMAGE_IMPORT_BY_NAME)
1013 ((ULONG_PTR)ImportBase +
1014 ((ULONG_PTR)OriginalThunk->u1.AddressOfData & 0xffffffff));
1015
1016 /* Get the name */
1017 ImportName = (LPSTR)AddressOfData->Name;
1018
1019 /* Now get the VA of the Name and Ordinal Tables */
1020 NameTable = (PULONG)((ULONG_PTR)ExportBase +
1021 (ULONG_PTR)ExportEntry->AddressOfNames);
1022 OrdinalTable = (PUSHORT)((ULONG_PTR)ExportBase +
1023 (ULONG_PTR)ExportEntry->AddressOfNameOrdinals);
1024
1025 /* Get the hint */
1026 Hint = AddressOfData->Hint;
1027
1028 /* Try to get a match by using the hint */
1029 if (((ULONG)Hint < ExportEntry->NumberOfNames) &&
1030 (!strcmp(ImportName, ((LPSTR)((ULONG_PTR)ExportBase + NameTable[Hint])))))
1031 {
1032 /* We got a match, get the Ordinal from the hint */
1033 Ordinal = OrdinalTable[Hint];
1034 }
1035 else
1036 {
1037 /* Well bummer, hint didn't work, do it the long way */
1038 Ordinal = LdrpNameToOrdinal(ImportName,
1039 ExportEntry->NumberOfNames,
1040 ExportBase,
1041 NameTable,
1042 OrdinalTable);
1043 }
1044 }
1045
1046 /* Check if the ordinal is invalid */
1047 if ((ULONG)Ordinal >= ExportEntry->NumberOfFunctions)
1048 {
1049 FailurePath:
1050 /* Is this a static snap? */
1051 if (Static)
1052 {
1053 /* Inform the debug log */
1054 if (IsOrdinal)
1055 DPRINT1("Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1056 else
1057 DPRINT1("Failed to snap %s\n", ImportName);
1058
1059 /* These are critical errors. Setup a string for the DLL name */
1060 RtlInitAnsiString(&TempString, DllName ? DllName : "Unknown");
1061 RtlAnsiStringToUnicodeString(&HardErrorDllName, &TempString, TRUE);
1062
1063 /* Set it as the parameter */
1064 HardErrorParameters[1] = (ULONG_PTR)&HardErrorDllName;
1065 Mask = 2;
1066
1067 /* Check if we have an ordinal */
1068 if (IsOrdinal)
1069 {
1070 /* Then set the ordinal as the 1st parameter */
1071 HardErrorParameters[0] = OriginalOrdinal;
1072 }
1073 else
1074 {
1075 /* We don't, use the entrypoint. Set up a string for it */
1076 RtlInitAnsiString(&TempString, ImportName);
1077 RtlAnsiStringToUnicodeString(&HardErrorEntryPointName,
1078 &TempString,
1079 TRUE);
1080
1081 /* Set it as the parameter */
1082 HardErrorParameters[0] = (ULONG_PTR)&HardErrorEntryPointName;
1083 Mask = 3;
1084 }
1085
1086 /* Raise the error */
1087 NtRaiseHardError(IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1088 STATUS_ENTRYPOINT_NOT_FOUND,
1089 2,
1090 Mask,
1091 HardErrorParameters,
1092 OptionOk,
1093 &Response);
1094
1095 /* Increase the error count */
1096 if (LdrpInLdrInit) LdrpFatalHardErrorCount++;
1097
1098 /* Free our string */
1099 RtlFreeUnicodeString(&HardErrorDllName);
1100 if (!IsOrdinal)
1101 {
1102 /* Free our second string. Return entrypoint error */
1103 RtlFreeUnicodeString(&HardErrorEntryPointName);
1104 RtlRaiseStatus(STATUS_ENTRYPOINT_NOT_FOUND);
1105 }
1106
1107 /* Return ordinal error */
1108 RtlRaiseStatus(STATUS_ORDINAL_NOT_FOUND);
1109 }
1110 else
1111 {
1112 /* Inform the debug log */
1113 if (IsOrdinal)
1114 DPRINT("Non-fatal: Failed to snap ordinal 0x%x\n", OriginalOrdinal);
1115 else
1116 DPRINT("Non-fatal: Failed to snap %s\n", ImportName);
1117 }
1118
1119 /* Set this as a bad DLL */
1120 Thunk->u1.Function = (ULONG_PTR)0xffbadd11;
1121
1122 /* Return the right error code */
1123 Status = IsOrdinal ? STATUS_ORDINAL_NOT_FOUND :
1124 STATUS_ENTRYPOINT_NOT_FOUND;
1125 }
1126 else
1127 {
1128 /* The ordinal seems correct, get the AddressOfFunctions VA */
1129 AddressOfFunctions = (PULONG)
1130 ((ULONG_PTR)ExportBase +
1131 (ULONG_PTR)ExportEntry->AddressOfFunctions);
1132
1133 /* Write the function pointer*/
1134 Thunk->u1.Function = (ULONG_PTR)ExportBase + AddressOfFunctions[Ordinal];
1135
1136 /* Make sure it's within the exports */
1137 if ((Thunk->u1.Function > (ULONG_PTR)ExportEntry) &&
1138 (Thunk->u1.Function < ((ULONG_PTR)ExportEntry + ExportSize)))
1139 {
1140 /* Get the Import and Forwarder Names */
1141 ImportName = (LPSTR)Thunk->u1.Function;
1142 ForwarderName.Buffer = ImportName;
1143 ForwarderName.Length = (USHORT)(strchr(ImportName, '.') - ImportName);
1144 ForwarderName.MaximumLength = ForwarderName.Length;
1145 Status = RtlAnsiStringToUnicodeString(&TempUString,
1146 &ForwarderName,
1147 TRUE);
1148
1149 /* Make sure the conversion was OK */
1150 if (NT_SUCCESS(Status))
1151 {
1152 /* Load the forwarder, free the temp string */
1153 Status = LdrpLoadDll(FALSE,
1154 NULL,
1155 NULL,
1156 &TempUString,
1157 &ForwarderHandle,
1158 FALSE);
1159 RtlFreeUnicodeString(&TempUString);
1160 }
1161
1162 /* If the load or conversion failed, use the failure path */
1163 if (!NT_SUCCESS(Status)) goto FailurePath;
1164
1165 /* Now set up a name for the actual forwarder dll */
1166 RtlInitAnsiString(&ForwarderName,
1167 ImportName + ForwarderName.Length + sizeof(CHAR));
1168
1169 /* Check if it's an ordinal forward */
1170 if ((ForwarderName.Length > 1) && (*ForwarderName.Buffer == '#'))
1171 {
1172 /* We don't have an actual function name */
1173 ForwardName = NULL;
1174
1175 /* Convert the string into an ordinal */
1176 Status = RtlCharToInteger(ForwarderName.Buffer + sizeof(CHAR),
1177 0,
1178 &ForwardOrdinal);
1179
1180 /* If this fails, then error out */
1181 if (!NT_SUCCESS(Status)) goto FailurePath;
1182 }
1183 else
1184 {
1185 /* Import by name */
1186 ForwardName = &ForwarderName;
1187 }
1188
1189 /* Get the pointer */
1190 Status = LdrpGetProcedureAddress(ForwarderHandle,
1191 ForwardName,
1192 ForwardOrdinal,
1193 (PVOID*)&Thunk->u1.Function,
1194 FALSE);
1195 /* If this fails, then error out */
1196 if (!NT_SUCCESS(Status)) goto FailurePath;
1197 }
1198 else
1199 {
1200 /* It's not within the exports, let's hope it's valid */
1201 if (!AddressOfFunctions[Ordinal]) goto FailurePath;
1202 }
1203
1204 /* If we got here, then it's success */
1205 Status = STATUS_SUCCESS;
1206 }
1207
1208 /* Return status */
1209 return Status;
1210 }
1211
1212 /* EOF */