[NTDLL/LDR]
[reactos.git] / reactos / 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 ULONG LdrpFatalHardErrorCount;
17 PVOID LdrpManifestProberRoutine;
18
19 /* PROTOTYPES ****************************************************************/
20
21 #define IMAGE_REL_BASED_HIGH3ADJ 11
22
23 NTSTATUS
24 NTAPI
25 LdrpLoadImportModule(IN PWSTR DllPath OPTIONAL,
26 IN LPSTR ImportName,
27 IN PVOID DllBase,
28 OUT PLDR_DATA_TABLE_ENTRY *DataTableEntry,
29 OUT PBOOLEAN Existing);
30
31 /* FUNCTIONS *****************************************************************/
32
33 NTSTATUS
34 NTAPI
35 LdrpSnapIAT(IN PLDR_DATA_TABLE_ENTRY ExportLdrEntry,
36 IN PLDR_DATA_TABLE_ENTRY ImportLdrEntry,
37 IN PIMAGE_IMPORT_DESCRIPTOR IatEntry,
38 IN BOOLEAN EntriesValid)
39 {
40 PIMAGE_EXPORT_DIRECTORY ExportDirectory;
41 ULONG ExportSize;
42 PVOID Iat;
43 SIZE_T ImportSize;
44 ULONG IatSize;
45 //PPEB Peb = NtCurrentPeb();
46 NTSTATUS Status;
47 PIMAGE_THUNK_DATA OriginalThunk, FirstThunk;
48 LPSTR ImportName;
49 ULONG ForwarderChain;
50 PIMAGE_NT_HEADERS NtHeader;
51 PIMAGE_SECTION_HEADER SectionHeader;
52 ULONG i, Rva;
53 ULONG OldProtect;
54
55 DPRINT("LdrpSnapIAT(%wZ %wZ %p %d)\n", &ExportLdrEntry->BaseDllName, &ImportLdrEntry->BaseDllName, IatEntry, EntriesValid);
56
57 /* Get export directory */
58 ExportDirectory = RtlImageDirectoryEntryToData(ExportLdrEntry->DllBase,
59 TRUE,
60 IMAGE_DIRECTORY_ENTRY_EXPORT,
61 &ExportSize);
62
63 /* Make sure it has one */
64 if (!ExportDirectory) return STATUS_INVALID_IMAGE_FORMAT;
65
66 /* Get the IAT */
67 Iat = RtlImageDirectoryEntryToData(ImportLdrEntry->DllBase,
68 TRUE,
69 IMAGE_DIRECTORY_ENTRY_IAT,
70 &IatSize);
71 ImportSize = IatSize;
72
73 /* Check if we don't have one */
74 if (!Iat)
75 {
76 /* Get the NT Header and the first section */
77 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
78 SectionHeader = IMAGE_FIRST_SECTION(NtHeader);
79
80 /* Get the RVA of the import directory */
81 Rva = NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
82
83 /* Make sure we got one */
84 if (Rva)
85 {
86 /* Loop all the sections */
87 for (i = 0; i < NtHeader->FileHeader.NumberOfSections; i++)
88 {
89 /* Check if we are inside this section */
90 if ((Rva >= SectionHeader->VirtualAddress) &&
91 (Rva < (SectionHeader->VirtualAddress +
92 SectionHeader->SizeOfRawData)))
93 {
94 /* We are, so set the IAT here */
95 Iat = (PVOID)((ULONG_PTR)(ImportLdrEntry->DllBase) +
96 SectionHeader->VirtualAddress);
97
98 /* Set the size */
99 IatSize = SectionHeader->Misc.VirtualSize;
100
101 /* Deal with Watcom and other retarded compilers */
102 if (!IatSize)
103 IatSize = SectionHeader->SizeOfRawData;
104
105 /* Found it, get out */
106 break;
107 }
108
109 /* No match, move to the next section */
110 SectionHeader++;
111 }
112 }
113
114 /* If we still don't have an IAT, that's bad */
115 if (!Iat) return STATUS_INVALID_IMAGE_FORMAT;
116
117 /* Set the right size */
118 ImportSize = IatSize;
119 }
120
121 /* Unprotect the IAT */
122 Status = NtProtectVirtualMemory(NtCurrentProcess(),
123 &Iat,
124 &ImportSize,
125 PAGE_READWRITE,
126 &OldProtect);
127 if (!NT_SUCCESS(Status)) return Status;
128
129 /* Check if the Thunks are already valid */
130 if (EntriesValid)
131 {
132 /* We'll only do forwarders. Get the import name */
133 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase + IatEntry->Name);
134
135 /* Get the list of forwaders */
136 ForwarderChain = IatEntry->ForwarderChain;
137
138 /* Loop them */
139 while (ForwarderChain != -1)
140 {
141 /* Get the cached thunk VA*/
142 OriginalThunk = (PIMAGE_THUNK_DATA)
143 ((ULONG_PTR)ImportLdrEntry->DllBase +
144 IatEntry->OriginalFirstThunk +
145 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
146
147 /* Get the first thunk */
148 FirstThunk = (PIMAGE_THUNK_DATA)
149 ((ULONG_PTR)ImportLdrEntry->DllBase +
150 IatEntry->FirstThunk +
151 (ForwarderChain * sizeof(IMAGE_THUNK_DATA)));
152
153 /* Get the Forwarder from the thunk */
154 ForwarderChain = (ULONG)FirstThunk->u1.Ordinal;
155
156 /* Snap the thunk */
157 _SEH2_TRY
158 {
159 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
160 ImportLdrEntry->DllBase,
161 OriginalThunk,
162 FirstThunk,
163 ExportDirectory,
164 ExportSize,
165 TRUE,
166 ImportName);
167
168 /* Move to the next thunk */
169 FirstThunk++;
170 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
171 {
172 /* Fail with the SEH error */
173 Status = _SEH2_GetExceptionCode();
174 } _SEH2_END;
175
176 /* If we messed up, exit */
177 if (!NT_SUCCESS(Status)) break;
178 }
179 }
180 else if (IatEntry->FirstThunk)
181 {
182 /* Full snapping. Get the First thunk */
183 FirstThunk = (PIMAGE_THUNK_DATA)
184 ((ULONG_PTR)ImportLdrEntry->DllBase +
185 IatEntry->FirstThunk);
186
187 /* Get the NT Header */
188 NtHeader = RtlImageNtHeader(ImportLdrEntry->DllBase);
189
190 /* Get the Original thunk VA, watch out for weird images */
191 if ((IatEntry->Characteristics < NtHeader->OptionalHeader.SizeOfHeaders) ||
192 (IatEntry->Characteristics >= NtHeader->OptionalHeader.SizeOfImage))
193 {
194 /* Refuse it, this is a strange linked file */
195 OriginalThunk = FirstThunk;
196 }
197 else
198 {
199 /* Get the address from the field and convert to VA */
200 OriginalThunk = (PIMAGE_THUNK_DATA)
201 ((ULONG_PTR)ImportLdrEntry->DllBase +
202 IatEntry->OriginalFirstThunk);
203 }
204
205 /* Get the Import name VA */
206 ImportName = (LPSTR)((ULONG_PTR)ImportLdrEntry->DllBase +
207 IatEntry->Name);
208
209 /* Loop while it's valid */
210 while (OriginalThunk->u1.AddressOfData)
211 {
212 /* Snap the Thunk */
213 _SEH2_TRY
214 {
215 Status = LdrpSnapThunk(ExportLdrEntry->DllBase,
216 ImportLdrEntry->DllBase,
217 OriginalThunk,
218 FirstThunk,
219 ExportDirectory,
220 ExportSize,
221 TRUE,
222 ImportName);
223
224 /* Next thunks */
225 OriginalThunk++;
226 FirstThunk++;
227 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
228 {
229 /* Fail with the SEH error */
230 Status = _SEH2_GetExceptionCode();
231 } _SEH2_END;
232
233 /* If we failed the snap, break out */
234 if (!NT_SUCCESS(Status)) break;
235 }
236 }
237
238 /* Protect the IAT again */
239 NtProtectVirtualMemory(NtCurrentProcess(),
240 &Iat,
241 &ImportSize,
242 OldProtect,
243 &OldProtect);
244
245 /* Also flush out the cache */
246 NtFlushInstructionCache(NtCurrentProcess(), Iat, IatSize);
247
248 /* Return to Caller */
249 return Status;
250 }
251
252 NTSTATUS
253 NTAPI
254 LdrpHandleOneNewFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
255 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
256 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR *BoundEntryPtr,
257 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry)
258 {
259 LPSTR ImportName = NULL, BoundImportName, ForwarderName;
260 NTSTATUS Status;
261 BOOLEAN AlreadyLoaded = FALSE, Stale;
262 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
263 PLDR_DATA_TABLE_ENTRY DllLdrEntry, ForwarderLdrEntry;
264 PIMAGE_BOUND_FORWARDER_REF ForwarderEntry;
265 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry;
266 PPEB Peb = NtCurrentPeb();
267 ULONG i, IatSize;
268
269 /* Get the pointer to the bound entry */
270 BoundEntry = *BoundEntryPtr;
271
272 /* Get the name's VA */
273 BoundImportName = (LPSTR)FirstEntry + BoundEntry->OffsetModuleName;
274
275 /* Show debug mesage */
276 if (ShowSnaps)
277 {
278 DPRINT1("LDR: %wZ bound to %s\n", &LdrEntry->BaseDllName, BoundImportName);
279 }
280
281 /* Load the module for this entry */
282 Status = LdrpLoadImportModule(DllPath,
283 BoundImportName,
284 LdrEntry->DllBase,
285 &DllLdrEntry,
286 &AlreadyLoaded);
287 if (!NT_SUCCESS(Status))
288 {
289 /* Show debug message */
290 if (ShowSnaps)
291 {
292 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
293 &LdrEntry->BaseDllName,
294 BoundImportName,
295 Status);
296 }
297 goto Quickie;
298 }
299
300 /* Check if it wasn't already loaded */
301 if (!AlreadyLoaded)
302 {
303 /* Add it to our list */
304 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
305 &DllLdrEntry->InInitializationOrderModuleList);
306 }
307
308 /* Check if the Bound Entry is now invalid */
309 if ((BoundEntry->TimeDateStamp != DllLdrEntry->TimeDateStamp) ||
310 (DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
311 {
312 /* Show debug message */
313 if (ShowSnaps)
314 {
315 DPRINT1("LDR: %wZ has stale binding to %s\n",
316 &LdrEntry->BaseDllName,
317 BoundImportName);
318 }
319
320 /* Remember it's become stale */
321 Stale = TRUE;
322 }
323 else
324 {
325 /* Show debug message */
326 if (ShowSnaps)
327 {
328 DPRINT1("LDR: %wZ has correct binding to %s\n",
329 &LdrEntry->BaseDllName,
330 BoundImportName);
331 }
332
333 /* Remember it's valid */
334 Stale = FALSE;
335 }
336
337 /* Get the forwarders */
338 ForwarderEntry = (PIMAGE_BOUND_FORWARDER_REF)(BoundEntry + 1);
339
340 /* Loop them */
341 for (i = 0; i < BoundEntry->NumberOfModuleForwarderRefs; i++)
342 {
343 /* Get the name */
344 ForwarderName = (LPSTR)FirstEntry + ForwarderEntry->OffsetModuleName;
345
346 /* Show debug message */
347 if (ShowSnaps)
348 {
349 DPRINT1("LDR: %wZ bound to %s via forwarder(s) from %wZ\n",
350 &LdrEntry->BaseDllName,
351 ForwarderName,
352 &DllLdrEntry->BaseDllName);
353 }
354
355 /* Load the module */
356 Status = LdrpLoadImportModule(DllPath,
357 ForwarderName,
358 LdrEntry->DllBase,
359 &ForwarderLdrEntry,
360 &AlreadyLoaded);
361 if (NT_SUCCESS(Status))
362 {
363 /* Loaded it, was it already loaded? */
364 if (!AlreadyLoaded)
365 {
366 /* Add it to our list */
367 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
368 &ForwarderLdrEntry->InInitializationOrderModuleList);
369 }
370 }
371
372 /* Check if the Bound Entry is now invalid */
373 if (!(NT_SUCCESS(Status)) ||
374 (ForwarderEntry->TimeDateStamp != ForwarderLdrEntry->TimeDateStamp) ||
375 (ForwarderLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE))
376 {
377 /* Show debug message */
378 if (ShowSnaps)
379 {
380 DPRINT1("LDR: %wZ has stale binding to %s\n",
381 &LdrEntry->BaseDllName,
382 ForwarderName);
383 }
384
385 /* Remember it's become stale */
386 Stale = TRUE;
387 }
388 else
389 {
390 /* Show debug message */
391 if (ShowSnaps)
392 {
393 DPRINT1("LDR: %wZ has correct binding to %s\n",
394 &LdrEntry->BaseDllName,
395 ForwarderName);
396 }
397
398 /* Remember it's valid */
399 Stale = FALSE;
400 }
401
402 /* Move to the next one */
403 ForwarderEntry++;
404 }
405
406 /* Set the next bound entry to the forwarder */
407 FirstEntry = (PIMAGE_BOUND_IMPORT_DESCRIPTOR)ForwarderEntry;
408
409 /* Check if the binding was stale */
410 if (Stale)
411 {
412 /* It was, so find the IAT entry for it */
413 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
414 TRUE,
415 IMAGE_DIRECTORY_ENTRY_IMPORT,
416 &IatSize);
417
418 /* Make sure it has a name */
419 while (ImportEntry->Name)
420 {
421 /* Get the name */
422 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
423
424 /* Compare it */
425 if (!_stricmp(ImportName, BoundImportName)) break;
426
427 /* Move to next entry */
428 ImportEntry++;
429 }
430
431 /* If we didn't find a name, fail */
432 if (!ImportEntry->Name)
433 {
434 /* Show debug message */
435 if (ShowSnaps)
436 {
437 DPRINT1("LDR: LdrpWalkImportTable - failing with"
438 "STATUS_OBJECT_NAME_INVALID due to no import descriptor name\n");
439 }
440
441 /* Return error */
442 Status = STATUS_OBJECT_NAME_INVALID;
443 goto Quickie;
444 }
445
446 /* Show debug message */
447 if (ShowSnaps)
448 {
449 DPRINT1("LDR: Stale Bind %s from %wZ\n",
450 ImportName,
451 &LdrEntry->BaseDllName);
452 }
453
454 /* Snap the IAT Entry*/
455 Status = LdrpSnapIAT(DllLdrEntry,
456 LdrEntry,
457 ImportEntry,
458 FALSE);
459
460 /* Make sure we didn't fail */
461 if (!NT_SUCCESS(Status))
462 {
463 /* Show debug message */
464 if (ShowSnaps)
465 {
466 DPRINT1("LDR: %wZ failed to load import module %s; status = %x\n",
467 &LdrEntry->BaseDllName,
468 BoundImportName,
469 Status);
470 }
471
472 /* Return */
473 goto Quickie;
474 }
475 }
476
477 /* All done */
478 Status = STATUS_SUCCESS;
479
480 Quickie:
481 /* Write where we are now and return */
482 *BoundEntryPtr = FirstEntry;
483 return Status;
484 }
485
486 NTSTATUS
487 NTAPI
488 LdrpHandleNewFormatImportDescriptors(IN LPWSTR DllPath OPTIONAL,
489 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
490 IN PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry)
491 {
492 PIMAGE_BOUND_IMPORT_DESCRIPTOR FirstEntry = BoundEntry;
493 NTSTATUS Status;
494
495 /* Make sure we have a name */
496 while (BoundEntry->OffsetModuleName)
497 {
498 /* Parse this descriptor */
499 Status = LdrpHandleOneNewFormatImportDescriptor(DllPath,
500 LdrEntry,
501 &BoundEntry,
502 FirstEntry);
503 if (!NT_SUCCESS(Status)) return Status;
504 }
505
506 /* Done */
507 return STATUS_SUCCESS;
508 }
509
510 NTSTATUS
511 NTAPI
512 LdrpHandleOneOldFormatImportDescriptor(IN LPWSTR DllPath OPTIONAL,
513 IN PLDR_DATA_TABLE_ENTRY LdrEntry,
514 IN PIMAGE_IMPORT_DESCRIPTOR ImportEntry)
515 {
516 //ULONG IatSize, i;
517 LPSTR ImportName;
518 NTSTATUS Status;
519 BOOLEAN AlreadyLoaded = FALSE, StaticEntriesValid = FALSE, SkipSnap = FALSE;
520 PLDR_DATA_TABLE_ENTRY DllLdrEntry;
521 PIMAGE_THUNK_DATA FirstThunk;
522 PPEB Peb = NtCurrentPeb();
523
524 /* Get the import name's VA */
525 ImportName = (LPSTR)((ULONG_PTR)LdrEntry->DllBase + ImportEntry->Name);
526
527 /* Get the first thunk */
528 FirstThunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)LdrEntry->DllBase +
529 ImportEntry->FirstThunk);
530
531 /* Make sure it's valid */
532 if (!FirstThunk->u1.Function) goto SkipEntry;
533
534 /* Show debug message */
535 if (ShowSnaps)
536 {
537 DPRINT1("LDR: %s used by %wZ\n",
538 ImportName,
539 &LdrEntry->BaseDllName);
540 }
541
542 /* Load the module associated to it */
543 Status = LdrpLoadImportModule(DllPath,
544 ImportName,
545 LdrEntry->DllBase,
546 &DllLdrEntry,
547 &AlreadyLoaded);
548 if (!NT_SUCCESS(Status)) return Status;
549
550 /* Show debug message */
551 if (ShowSnaps)
552 {
553 DPRINT1("LDR: Snapping imports for %wZ from %s\n",
554 &LdrEntry->BaseDllName,
555 ImportName);
556 }
557
558 /* Check if the image was bound when compiled */
559 if (ImportEntry->OriginalFirstThunk)
560 {
561 /* It was, so check if the static IAT entries are still valid */
562 if ((ImportEntry->TimeDateStamp) &&
563 (ImportEntry->TimeDateStamp == DllLdrEntry->TimeDateStamp) &&
564 (!(DllLdrEntry->Flags & LDRP_IMAGE_NOT_AT_BASE)))
565 {
566 /* Show debug message */
567 if (ShowSnaps)
568 {
569 DPRINT1("LDR: Snap bypass %s from %wZ\n",
570 ImportName,
571 &LdrEntry->BaseDllName);
572 }
573
574 /*
575 * They are still valid, so we can skip snapping them.
576 * Additionally, if we have no forwarders, we are totally
577 * done.
578 */
579 if (ImportEntry->ForwarderChain == -1)
580 {
581 /* Totally skip LdrpSnapIAT */
582 SkipSnap = TRUE;
583 }
584 else
585 {
586 /* Set this so LdrpSnapIAT will only do forwarders */
587 StaticEntriesValid = TRUE;
588 }
589 }
590 }
591
592 /* Check if it wasn't already loaded */
593 if (!AlreadyLoaded)
594 {
595 /* Add the DLL to our list */
596 InsertTailList(&Peb->Ldr->InInitializationOrderModuleList,
597 &DllLdrEntry->InInitializationOrderModuleList);
598 }
599
600 /* Check if we should snap at all */
601 if (!SkipSnap)
602 {
603 /* Now snap the IAT Entry */
604 Status = LdrpSnapIAT(DllLdrEntry,
605 LdrEntry,
606 ImportEntry,
607 StaticEntriesValid);
608 if (!NT_SUCCESS(Status)) return Status;
609 }
610
611 SkipEntry:
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 /* Move to the next entry */
633 ImportEntry++;
634 }
635
636 /* Done */
637 return STATUS_SUCCESS;
638 }
639
640 USHORT NTAPI
641 LdrpNameToOrdinal(LPSTR ImportName,
642 ULONG NumberOfNames,
643 PVOID ExportBase,
644 PULONG NameTable,
645 PUSHORT OrdinalTable)
646 {
647 ULONG Start, End, Next;
648 LONG CmpResult;
649
650 /* Use classical binary search to find the ordinal */
651 Start = 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 End = Next - 1;
667 else if (CmpResult > 0)
668 Start = Next + 1;
669 }
670
671 /* If end is before start, then the search failed */
672 if (End < Start) return -1;
673
674 /* Return found name */
675 return OrdinalTable[Next];
676 }
677
678 NTSTATUS
679 NTAPI
680 LdrpWalkImportDescriptor(IN LPWSTR DllPath OPTIONAL,
681 IN PLDR_DATA_TABLE_ENTRY LdrEntry)
682 {
683 RTL_CALLER_ALLOCATED_ACTIVATION_CONTEXT_STACK_FRAME_EXTENDED ActCtx;
684 PPEB Peb = NtCurrentPeb();
685 NTSTATUS Status = STATUS_SUCCESS;
686 PIMAGE_BOUND_IMPORT_DESCRIPTOR BoundEntry = NULL;
687 PIMAGE_IMPORT_DESCRIPTOR ImportEntry;
688 ULONG BoundSize, IatSize;
689
690 DPRINT("LdrpWalkImportDescriptor('%S' %x)\n", DllPath, LdrEntry);
691
692 /* Set up the Act Ctx */
693 ActCtx.Size = sizeof(ActCtx);
694 ActCtx.Format = 1;
695 RtlZeroMemory(&ActCtx.Frame, sizeof(RTL_ACTIVATION_CONTEXT_STACK_FRAME));
696
697 /* Check if we have a manifest prober routine */
698 if (LdrpManifestProberRoutine)
699 {
700 DPRINT1("We don't support manifests yet, much less prober routines\n");
701 }
702
703 /* Check if we failed above */
704 if (!NT_SUCCESS(Status)) return Status;
705
706 /* Get the Active ActCtx */
707 Status = RtlGetActiveActivationContext(&LdrEntry->EntryPointActivationContext);
708 if (!NT_SUCCESS(Status)) return Status;
709
710 /* Activate the ActCtx */
711 RtlActivateActivationContextUnsafeFast(&ActCtx,
712 LdrEntry->EntryPointActivationContext);
713
714 /* Check if we were redirected */
715 if (!(LdrEntry->Flags & LDRP_REDIRECTED))
716 {
717 /* Get the Bound IAT */
718 BoundEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
719 TRUE,
720 IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
721 &BoundSize);
722 }
723
724 /* Get the regular IAT, for fallback */
725 ImportEntry = RtlImageDirectoryEntryToData(LdrEntry->DllBase,
726 TRUE,
727 IMAGE_DIRECTORY_ENTRY_IMPORT,
728 &IatSize);
729
730 /* Check if we got at least one */
731 if (BoundEntry || ImportEntry)
732 {
733 /* Do we have a Bound IAT */
734 if (BoundEntry)
735 {
736 /* Handle the descriptor */
737 Status = LdrpHandleNewFormatImportDescriptors(DllPath,
738 LdrEntry,
739 BoundEntry);
740 }
741 else
742 {
743 /* Handle the descriptor */
744 Status = LdrpHandleOldFormatImportDescriptors(DllPath,
745 LdrEntry,
746 ImportEntry);
747 }
748
749 /* Check the status of the handlers */
750 if (NT_SUCCESS(Status))
751 {
752 /* Check for Per-DLL Heap Tagging */
753 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAG_BY_DLL)
754 {
755 /* FIXME */
756 DPRINT1("We don't support Per-DLL Heap Tagging yet!\n");
757 }
758
759 /* Check if Page Heap was enabled */
760 if (Peb->NtGlobalFlag & FLG_HEAP_PAGE_ALLOCS)
761 {
762 /* FIXME */
763 DPRINT1("We don't support Page Heaps yet!\n");
764 }
765
766 /* Check if Application Verifier was enabled */
767 if (Peb->NtGlobalFlag & FLG_HEAP_ENABLE_TAIL_CHECK)
768 {
769 /* FIXME */
770 DPRINT1("We don't support Application Verifier yet!\n");
771 }
772
773 /* Just to be safe */
774 Status = STATUS_SUCCESS;
775 }
776 }
777
778 /* Release the activation context */
779 RtlDeactivateActivationContextUnsafeFast(&ActCtx);
780
781 /* Return status */
782 return Status;
783 }
784
785 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 */