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